Change:
At the moment WF checking is not done via a query. As a consequence, we cannot cache it during incremental compilation. Seems like an easy optimization. cc
I'm working on this.

Discussion:
[] GetPanicStrategy(CrateNum), [] IsNoBuiltins(CrateNum), [] ImplDefaultness(DefId), <ins> [] CheckItemWellFormed(DefId), [] CheckTraitItemWellFormed(DefId), [] CheckImplItemWellFormed(DefId), </ins> [] ReachableNonGenerics(CrateNum), [] NativeLibraries(CrateNum), [] PluginRegistrarFn(CrateNum),

[] fn impl_defaultness: ImplDefaultness(DefId) -> hir::Defaultness, <ins> [] fn check_item_well_formed: CheckItemWellFormed(DefId) -> (), [] fn check_trait_item_well_formed: CheckTraitItemWellFormed(DefId) -> (), [] fn check_impl_item_well_formed: CheckImplItemWellFormed(DefId) -> (), </ins> // The DefIds of all non-generic functions and statics in the given crate // that can be reached from outside the crate. //

DepKind::GetPanicStrategy => { force!(panic_strategy, krate!()); } DepKind::IsNoBuiltins => { force!(is_no_builtins, krate!()); } DepKind::ImplDefaultness => { force!(impl_defaultness, def_id!()); } <ins> DepKind::CheckItemWellFormed => { force!(check_item_well_formed, def_id!()); } DepKind::CheckTraitItemWellFormed => { force!(check_trait_item_well_formed, def_id!()); } DepKind::CheckImplItemWellFormed => { force!(check_impl_item_well_formed, def_id!()); } </ins> DepKind::ReachableNonGenerics => { force!(reachable_non_generics, krate!()); } DepKind::NativeLibraries => { force!(native_libraries, krate!()); } DepKind::PluginRegistrarFn => { force!(plugin_registrar_fn, krate!()); }

})?) } <ins> fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { wfcheck::check_item_well_formed(tcx, def_id); } fn check_trait_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { wfcheck::check_trait_item(tcx, def_id); } fn check_impl_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { wfcheck::check_impl_item(tcx, def_id); } </ins> pub fn provide(providers: &mut Providers) { *providers = Providers { typeck_item_bodies,

has_typeck_tables, adt_destructor, used_trait_imports, <ins> check_item_well_formed, check_trait_item_well_formed, check_impl_item_well_formed, </ins> ..*providers }; }

use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir; <del> pub struct CheckTypeWellFormedVisitor<'a, 'tcx:'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, code: ObligationCauseCode<'tcx>, } </del> /// Helper type of a temporary returned by .for_item(...). /// Necessary because we can't write the following bound: /// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(FnCtxt<'b, 'gcx, 'tcx>). struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { inherited: super::InheritedBuilder<'a, 'gcx, 'tcx>, <del> code: ObligationCauseCode<'gcx>, </del> id: ast::NodeId, span: Span, param_env: ty::ParamEnv<'tcx>,

impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { fn with_fcx<F>(&'tcx mut self, f: F) where F: for<'b> FnOnce(&FnCtxt<'b, 'gcx, 'tcx>, <del> &mut CheckTypeWellFormedVisitor<'b, 'gcx>) -> Vec<Ty<'tcx>> </del> <ins> TyCtxt<'b, 'gcx, 'gcx>) -> Vec<Ty<'tcx>> </ins> { <del> let code = self.code.clone(); </del> let id = self.id; let span = self.span; let param_env = self.param_env; self.inherited.enter(|inh| { let fcx = FnCtxt::new(&inh, param_env, id); <del> let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor { tcx: fcx.tcx.global_tcx(), code, }); </del> <ins> let wf_tys = f(&fcx, fcx.tcx.global_tcx()); </ins> fcx.select_all_obligations_or_error(); fcx.regionck_item(id, span, &wf_tys); }); } } <del> impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { pub fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>) -> CheckTypeWellFormedVisitor<'a, 'gcx> { CheckTypeWellFormedVisitor { tcx, code: ObligationCauseCode::MiscObligation } } /// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are /// well-formed, meaning that they do not require any constraints not declared in the struct /// definition itself. For example, this definition would be illegal: /// ///     struct Ref<'a, T> { x: &'a T } /// /// because the type did not declare that `T:'a`. /// /// We do this check as a pre-pass before checking fn bodies because if these constraints are /// not included it frequently leads to confusing errors in fn bodies. So it's better to check /// the types first. fn check_item_well_formed(&mut self, item: &hir::Item) { let tcx = self.tcx; debug!("check_item_well_formed(it.id={}, it.name={})", item.id, tcx.item_path_str(tcx.hir.local_def_id(item.id))); match item.node { // Right now we check that every default trait implementation // has an implementation of itself. Basically, a case like: // // `impl Trait for T {}` // // has a requirement of `T: Trait` which was required for default // method implementations. Although this could be improved now that // there's a better infrastructure in place for this, it's being left // for a follow-up work. // // Since there's such a requirement, we need to check *just* positive // implementations, otherwise things like: // // impl !Send for T {} // // won't be allowed unless there's an *explicit* implementation of `Send` // for `T` hir::ItemImpl(_, polarity, defaultness, _, ref trait_ref, ref self_ty, _) => { let is_auto = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id)) .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id)); if let (hir::Defaultness::Default { .. }, true) = (defaultness, is_auto) { tcx.sess.span_err(item.span, "impls of auto traits cannot be default"); } if polarity == hir::ImplPolarity::Positive { self.check_impl(item, self_ty, trait_ref); } else { // FIXME(#27579) what amount of WF checking do we need for neg impls? if trait_ref.is_some() && !is_auto { span_err!(tcx.sess, item.span, E0192, "negative impls are only allowed for  auto traits (e.g., `Send` and `Sync`)") } } } hir::ItemFn(..) => { self.check_item_fn(item); } hir::ItemStatic(..) => { self.check_item_type(item); </del> <ins> /// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are /// well-formed, meaning that they do not require any constraints not declared in the struct /// definition itself. For example, this definition would be illegal: /// ///     struct Ref<'a, T> { x: &'a T } /// /// because the type did not declare that `T:'a`. /// /// We do this check as a pre-pass before checking fn bodies because if these constraints are /// not included it frequently leads to confusing errors in fn bodies. So it's better to check /// the types first. pub fn check_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); let item = tcx.hir.expect_item(node_id); debug!("check_item_well_formed(it.id={}, it.name={})", item.id, tcx.item_path_str(def_id)); match item.node { // Right now we check that every default trait implementation // has an implementation of itself. Basically, a case like: // // `impl Trait for T {}` // // has a requirement of `T: Trait` which was required for default // method implementations. Although this could be improved now that // there's a better infrastructure in place for this, it's being left // for a follow-up work. // // Since there's such a requirement, we need to check *just* positive // implementations, otherwise things like: // // impl !Send for T {} // // won't be allowed unless there's an *explicit* implementation of `Send` // for `T` hir::ItemImpl(_, polarity, defaultness, _, ref trait_ref, ref self_ty, _) => { let is_auto = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id)) .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id)); if let (hir::Defaultness::Default { .. }, true) = (defaultness, is_auto) { tcx.sess.span_err(item.span, "impls of auto traits cannot be default"); </ins> } <del> hir::ItemConst(..) => { self.check_item_type(item); </del> <ins> if polarity == hir::ImplPolarity::Positive { check_impl(tcx, item, self_ty, trait_ref); } else { // FIXME(#27579) what amount of WF checking do we need for neg impls? if trait_ref.is_some() && !is_auto { span_err!(tcx.sess, item.span, E0192, "negative impls are only allowed for  auto traits (e.g., `Send` and `Sync`)") } </ins> } <del> hir::ItemStruct(ref struct_def, ref ast_generics) => { self.check_type_defn(item, false, |fcx| { vec![fcx.non_enum_variant(struct_def)] }); </del> <ins> } hir::ItemFn(..) => { check_item_fn(tcx, item); } hir::ItemStatic(..) => { check_item_type(tcx, item); } hir::ItemConst(..) => { check_item_type(tcx, item); } hir::ItemStruct(ref struct_def, ref ast_generics) => { check_type_defn(tcx, item, false, |fcx| { vec![fcx.non_enum_variant(struct_def)] }); </ins> <del> self.check_variances_for_type_defn(item, ast_generics); } hir::ItemUnion(ref struct_def, ref ast_generics) => { self.check_type_defn(item, true, |fcx| { vec![fcx.non_enum_variant(struct_def)] }); </del> <ins> check_variances_for_type_defn(tcx, item, ast_generics); } hir::ItemUnion(ref struct_def, ref ast_generics) => { check_type_defn(tcx, item, true, |fcx| { vec![fcx.non_enum_variant(struct_def)] }); </ins> <del> self.check_variances_for_type_defn(item, ast_generics); } hir::ItemEnum(ref enum_def, ref ast_generics) => { self.check_type_defn(item, true, |fcx| { fcx.enum_variants(enum_def) }); </del> <ins> check_variances_for_type_defn(tcx, item, ast_generics); } hir::ItemEnum(ref enum_def, ref ast_generics) => { check_type_defn(tcx, item, true, |fcx| { fcx.enum_variants(enum_def) }); </ins> <del> self.check_variances_for_type_defn(item, ast_generics); } hir::ItemTrait(..) => { self.check_trait(item); } _ => {} </del> <ins> check_variances_for_type_defn(tcx, item, ast_generics); </ins> } <ins> hir::ItemTrait(..) => { check_trait(tcx, item); } _ => {} </ins> } <ins> } </ins> <del> fn check_associated_item(&mut self, item_id: ast::NodeId, span: Span, sig_if_method: Option<&hir::MethodSig>) { let code = self.code.clone(); self.for_id(item_id, span).with_fcx(|fcx, this| { let item = fcx.tcx.associated_item(fcx.tcx.hir.local_def_id(item_id)); let (mut implied_bounds, self_ty) = match item.container { ty::TraitContainer(_) => (vec![], fcx.tcx.mk_self_type()), ty::ImplContainer(def_id) => (fcx.impl_implied_bounds(def_id, span), fcx.tcx.type_of(def_id)) }; </del> <ins> pub fn check_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); let trait_item = tcx.hir.expect_trait_item(node_id); let method_sig = match trait_item.node { hir::TraitItemKind::Method(ref sig, _) => Some(sig), _ => None }; check_associated_item(tcx, trait_item.id, trait_item.span, method_sig); } pub fn check_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); let impl_item = tcx.hir.expect_impl_item(node_id); let method_sig = match impl_item.node { hir::ImplItemKind::Method(ref sig, _) => Some(sig), _ => None }; check_associated_item(tcx, impl_item.id, impl_item.span, method_sig); } fn check_associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId, span: Span, sig_if_method: Option<&hir::MethodSig>) { let code = ObligationCauseCode::MiscObligation; for_id(tcx, item_id, span).with_fcx(|fcx, tcx| { let item = fcx.tcx.associated_item(fcx.tcx.hir.local_def_id(item_id)); let (mut implied_bounds, self_ty) = match item.container { ty::TraitContainer(_) => (vec![], fcx.tcx.mk_self_type()), ty::ImplContainer(def_id) => (fcx.impl_implied_bounds(def_id, span), fcx.tcx.type_of(def_id)) }; </ins> <del> match item.kind { ty::AssociatedKind::Const => { </del> <ins> match item.kind { ty::AssociatedKind::Const => { let ty = fcx.tcx.type_of(item.def_id); let ty = fcx.normalize_associated_types_in(span, &ty); fcx.register_wf_obligation(ty, span, code.clone()); } ty::AssociatedKind::Method => { reject_shadowing_type_parameters(fcx.tcx, item.def_id); let sig = fcx.tcx.fn_sig(item.def_id); let sig = fcx.normalize_associated_types_in(span, &sig); check_fn_or_method(tcx, fcx, span, sig, item.def_id, &mut implied_bounds); let sig_if_method = sig_if_method.expect("bad signature for method"); check_method_receiver(fcx, sig_if_method, &item, self_ty); } ty::AssociatedKind::Type => { if item.defaultness.has_value() { </ins> let ty = fcx.tcx.type_of(item.def_id); let ty = fcx.normalize_associated_types_in(span, &ty); fcx.register_wf_obligation(ty, span, code.clone()); } <del> ty::AssociatedKind::Method => { reject_shadowing_type_parameters(fcx.tcx, item.def_id); let sig = fcx.tcx.fn_sig(item.def_id); let sig = fcx.normalize_associated_types_in(span, &sig); this.check_fn_or_method(fcx, span, sig, item.def_id, &mut implied_bounds); let sig_if_method = sig_if_method.expect("bad signature for method"); this.check_method_receiver(fcx, sig_if_method, &item, self_ty); } ty::AssociatedKind::Type => { if item.defaultness.has_value() { let ty = fcx.tcx.type_of(item.def_id); let ty = fcx.normalize_associated_types_in(span, &ty); fcx.register_wf_obligation(ty, span, code.clone()); } } </del> } <ins> } </ins> <del> implied_bounds }) } fn for_item<'tcx>(&self, item: &hir::Item) -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { self.for_id(item.id, item.span) } </del> <ins> implied_bounds }) } </ins> <del> fn for_id<'tcx>(&self, id: ast::NodeId, span: Span) </del> <ins> fn for_item<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, item: &hir::Item) </ins> -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { <del> let def_id = self.tcx.hir.local_def_id(id); CheckWfFcxBuilder { inherited: Inherited::build(self.tcx, def_id), code: self.code.clone(), id, span, param_env: self.tcx.param_env(def_id), } </del> <ins> for_id(tcx, item.id, item.span) } fn for_id<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, id: ast::NodeId, span: Span) -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> { let def_id = tcx.hir.local_def_id(id); CheckWfFcxBuilder { inherited: Inherited::build(tcx, def_id), id, span, param_env: tcx.param_env(def_id), </ins> } <ins> } </ins> <del> /// In a type definition, we check that to ensure that the types of the fields are well-formed. fn check_type_defn<F>(&mut self, item: &hir::Item, all_sized: bool, mut lookup_fields: F) where F: for<'fcx, 'tcx> FnMut(&FnCtxt<'fcx, 'gcx, 'tcx>) -> Vec<AdtVariant<'tcx>> { self.for_item(item).with_fcx(|fcx, this| { let variants = lookup_fields(fcx); let def_id = fcx.tcx.hir.local_def_id(item.id); let packed = fcx.tcx.adt_def(def_id).repr.packed(); for variant in &variants { // For DST, or when drop needs to copy things around, all // intermediate types must be sized. let needs_drop_copy = || { packed && { let ty = variant.fields.last().unwrap().ty; let ty = fcx.tcx.erase_regions(&ty).lift_to_tcx(this.tcx) .unwrap_or_else(|| { span_bug!(item.span, "inference variables in {:?}", ty) }); ty.needs_drop(this.tcx, this.tcx.param_env(def_id)) } }; let unsized_len = if all_sized || variant.fields.is_empty() || needs_drop_copy() { 0 } else { 1 }; for field in &variant.fields[..variant.fields.len() - unsized_len] { fcx.register_bound( field.ty, fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem), traits::ObligationCause::new(field.span, fcx.body_id, traits::FieldSized(match item.node.adt_kind() { Some(i) => i, None => bug!(), }))); </del> <ins> /// In a type definition, we check that to ensure that the types of the fields are well-formed. fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item, all_sized: bool, mut lookup_fields: F) where F: for<'fcx, 'gcx, 'tcx2> FnMut(&FnCtxt<'fcx, 'gcx, 'tcx2>) -> Vec<AdtVariant<'tcx2>> { for_item(tcx, item).with_fcx(|fcx, fcx_tcx| { let variants = lookup_fields(fcx); let def_id = fcx.tcx.hir.local_def_id(item.id); let packed = fcx.tcx.adt_def(def_id).repr.packed(); for variant in &variants { // For DST, or when drop needs to copy things around, all // intermediate types must be sized. let needs_drop_copy = || { packed && { let ty = variant.fields.last().unwrap().ty; let ty = fcx.tcx.erase_regions(&ty).lift_to_tcx(fcx_tcx) .unwrap_or_else(|| { span_bug!(item.span, "inference variables in {:?}", ty) }); ty.needs_drop(fcx_tcx, fcx_tcx.param_env(def_id)) </ins> } <ins> }; let unsized_len = if all_sized || variant.fields.is_empty() || needs_drop_copy() { 0 } else { 1 }; for field in &variant.fields[..variant.fields.len() - unsized_len] { fcx.register_bound( field.ty, fcx.tcx.require_lang_item(lang_items::SizedTraitLangItem), traits::ObligationCause::new(field.span, fcx.body_id, traits::FieldSized(match item.node.adt_kind() { Some(i) => i, None => bug!(), }))); } </ins> <del> // All field types must be well-formed. for field in &variant.fields { fcx.register_wf_obligation(field.ty, field.span, this.code.clone()) } </del> <ins> // All field types must be well-formed. for field in &variant.fields { fcx.register_wf_obligation(field.ty, field.span, ObligationCauseCode::MiscObligation) </ins> } <ins> } </ins> <del> self.check_where_clauses(fcx, item.span, def_id); </del> <ins> check_where_clauses(tcx, fcx, item.span, def_id); </ins> <del> vec![] // no implied bounds in a struct def'n }); } </del> <ins> vec![] // no implied bounds in a struct def'n }); } </ins> <del> fn check_trait(&mut self, item: &hir::Item) { let trait_def_id = self.tcx.hir.local_def_id(item.id); self.for_item(item).with_fcx(|fcx, _| { self.check_where_clauses(fcx, item.span, trait_def_id); vec![] }); } </del> <ins> fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) { let trait_def_id = tcx.hir.local_def_id(item.id); for_item(tcx, item).with_fcx(|fcx, _| { check_where_clauses(tcx, fcx, item.span, trait_def_id); vec![] }); } </ins> <del> fn check_item_fn(&mut self, item: &hir::Item) { self.for_item(item).with_fcx(|fcx, this| { let def_id = fcx.tcx.hir.local_def_id(item.id); let sig = fcx.tcx.fn_sig(def_id); let sig = fcx.normalize_associated_types_in(item.span, &sig); let mut implied_bounds = vec![]; this.check_fn_or_method(fcx, item.span, sig, def_id, &mut implied_bounds); implied_bounds }) } </del> <ins> fn check_item_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) { for_item(tcx, item).with_fcx(|fcx, tcx| { let def_id = fcx.tcx.hir.local_def_id(item.id); let sig = fcx.tcx.fn_sig(def_id); let sig = fcx.normalize_associated_types_in(item.span, &sig); let mut implied_bounds = vec![]; check_fn_or_method(tcx, fcx, item.span, sig, def_id, &mut implied_bounds); implied_bounds }) } </ins> <del> fn check_item_type(&mut self, item: &hir::Item) { debug!("check_item_type: {:?}", item); </del> <ins> fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) { debug!("check_item_type: {:?}", item); </ins> <del> self.for_item(item).with_fcx(|fcx, this| { let ty = fcx.tcx.type_of(fcx.tcx.hir.local_def_id(item.id)); let item_ty = fcx.normalize_associated_types_in(item.span, &ty); </del> <ins> for_item(tcx, item).with_fcx(|fcx, _this| { let ty = fcx.tcx.type_of(fcx.tcx.hir.local_def_id(item.id)); let item_ty = fcx.normalize_associated_types_in(item.span, &ty); </ins> <del> fcx.register_wf_obligation(item_ty, item.span, this.code.clone()); </del> <ins> fcx.register_wf_obligation(item_ty, item.span, ObligationCauseCode::MiscObligation); </ins> <del> vec![] // no implied bounds in a const etc }); } </del> <ins> vec![] // no implied bounds in a const etc }); } </ins> <del> fn check_impl(&mut self, item: &hir::Item, ast_self_ty: &hir::Ty, ast_trait_ref: &Option<hir::TraitRef>) { debug!("check_impl: {:?}", item); self.for_item(item).with_fcx(|fcx, this| { let item_def_id = fcx.tcx.hir.local_def_id(item.id); match *ast_trait_ref { Some(ref ast_trait_ref) => { let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap(); let trait_ref = fcx.normalize_associated_types_in( ast_trait_ref.path.span, &trait_ref); let obligations = ty::wf::trait_obligations(fcx, fcx.param_env, fcx.body_id, &trait_ref, ast_trait_ref.path.span); for obligation in obligations { fcx.register_predicate(obligation); } } None => { let self_ty = fcx.tcx.type_of(item_def_id); let self_ty = fcx.normalize_associated_types_in(item.span, &self_ty); fcx.register_wf_obligation(self_ty, ast_self_ty.span, this.code.clone()); </del> <ins> fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item, ast_self_ty: &hir::Ty, ast_trait_ref: &Option<hir::TraitRef>) { debug!("check_impl: {:?}", item); for_item(tcx, item).with_fcx(|fcx, tcx| { let item_def_id = fcx.tcx.hir.local_def_id(item.id); match *ast_trait_ref { Some(ref ast_trait_ref) => { let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap(); let trait_ref = fcx.normalize_associated_types_in( ast_trait_ref.path.span, &trait_ref); let obligations = ty::wf::trait_obligations(fcx, fcx.param_env, fcx.body_id, &trait_ref, ast_trait_ref.path.span); for obligation in obligations { fcx.register_predicate(obligation); </ins> } } <ins> None => { let self_ty = fcx.tcx.type_of(item_def_id); let self_ty = fcx.normalize_associated_types_in(item.span, &self_ty); fcx.register_wf_obligation(self_ty, ast_self_ty.span, ObligationCauseCode::MiscObligation); } } </ins> <del> this.check_where_clauses(fcx, item.span, item_def_id); </del> <ins> check_where_clauses(tcx, fcx, item.span, item_def_id); </ins> <del> fcx.impl_implied_bounds(item_def_id, item.span) }); } </del> <ins> fcx.impl_implied_bounds(item_def_id, item.span) }); } </ins> <del> /// Checks where clauses and inline bounds that are declared on def_id. fn check_where_clauses<'fcx, 'tcx>(&mut self, fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, span: Span, def_id: DefId) { use ty::subst::Subst; use rustc::ty::TypeFoldable; let mut predicates = fcx.tcx.predicates_of(def_id); let mut substituted_predicates = Vec::new(); let generics = self.tcx.generics_of(def_id); let is_our_default = |def: &ty::TypeParameterDef| def.has_default && def.index >= generics.parent_count() as u32; // Check that concrete defaults are well-formed. See test `type-check-defaults.rs`. // For example this forbids the declaration: // struct Foo<T = Vec<[u32]>> { .. } // Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold. for d in generics.types.iter().cloned().filter(is_our_default).map(|p| p.def_id) { let ty = fcx.tcx.type_of(d); // ignore dependent defaults -- that is, where the default of one type // parameter includes another (e.g., <T, U = T>). In those cases, we can't // be sure if it will error or not as user might always specify the other. if !ty.needs_subst() { fcx.register_wf_obligation(ty, fcx.tcx.def_span(d), self.code.clone()); } </del> <ins> /// Checks where clauses and inline bounds that are declared on def_id. fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, span: Span, def_id: DefId) { use ty::subst::Subst; use rustc::ty::TypeFoldable; let mut predicates = fcx.tcx.predicates_of(def_id); let mut substituted_predicates = Vec::new(); let generics = tcx.generics_of(def_id); let is_our_default = |def: &ty::TypeParameterDef| def.has_default && def.index >= generics.parent_count() as u32; // Check that concrete defaults are well-formed. See test `type-check-defaults.rs`. // For example this forbids the declaration: // struct Foo<T = Vec<[u32]>> { .. } // Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold. for d in generics.types.iter().cloned().filter(is_our_default).map(|p| p.def_id) { let ty = fcx.tcx.type_of(d); // ignore dependent defaults -- that is, where the default of one type // parameter includes another (e.g., <T, U = T>). In those cases, we can't // be sure if it will error or not as user might always specify the other. if !ty.needs_subst() { fcx.register_wf_obligation(ty, fcx.tcx.def_span(d), ObligationCauseCode::MiscObligation); </ins> } <ins> } </ins> <del> // Check that trait predicates are WF when params are substituted by their defaults. // We don't want to overly constrain the predicates that may be written but we want to // catch cases where a default my never be applied such as `struct Foo<T: Copy = String>`. // Therefore we check if a predicate which contains a single type param // with a concrete default is WF with that default substituted. // For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`. // // First we build the defaulted substitution. let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| { // All regions are identity. fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data())) }, |def, _| { // If the param has a default, if is_our_default(def) { let default_ty = fcx.tcx.type_of(def.def_id); // and it's not a dependent default if !default_ty.needs_subst() { // then substitute with the default. return default_ty; } </del> <ins> // Check that trait predicates are WF when params are substituted by their defaults. // We don't want to overly constrain the predicates that may be written but we want to // catch cases where a default my never be applied such as `struct Foo<T: Copy = String>`. // Therefore we check if a predicate which contains a single type param // with a concrete default is WF with that default substituted. // For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`. // // First we build the defaulted substitution. let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| { // All regions are identity. fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data())) }, |def, _| { // If the param has a default, if is_our_default(def) { let default_ty = fcx.tcx.type_of(def.def_id); // and it's not a dependent default if !default_ty.needs_subst() { // then substitute with the default. return default_ty; </ins> } <del> // Mark unwanted params as err. fcx.tcx.types.err }); // Now we build the substituted predicates. for &pred in predicates.predicates.iter() { struct CountParams { params: FxHashSet<u32> } impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { match t.sty { ty::TyParam(p) => { self.params.insert(p.idx); t.super_visit_with(self) } _ => t.super_visit_with(self) </del> <ins> } // Mark unwanted params as err. fcx.tcx.types.err }); // Now we build the substituted predicates. for &pred in predicates.predicates.iter() { struct CountParams { params: FxHashSet<u32> } impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { match t.sty { ty::TyParam(p) => { self.params.insert(p.idx); t.super_visit_with(self) </ins> } <ins> _ => t.super_visit_with(self) </ins> } } <del> let mut param_count = CountParams { params: FxHashSet() }; pred.visit_with(&mut param_count); let substituted_pred = pred.subst(fcx.tcx, substs); // Don't check non-defaulted params, dependent defaults or preds with multiple params. if substituted_pred.references_error() || param_count.params.len() > 1 { continue; } // Avoid duplication of predicates that contain no parameters, for example. if !predicates.predicates.contains(&substituted_pred) { substituted_predicates.push(substituted_pred); } </del> } <del> predicates.predicates.extend(substituted_predicates); let predicates = predicates.instantiate_identity(fcx.tcx); let predicates = fcx.normalize_associated_types_in(span, &predicates); let obligations = predicates.predicates .iter() .flat_map(|p| ty::wf::predicate_obligations(fcx, fcx.param_env, fcx.body_id, p, span)); for obligation in obligations { fcx.register_predicate(obligation); </del> <ins> let mut param_count = CountParams { params: FxHashSet() }; pred.visit_with(&mut param_count); let substituted_pred = pred.subst(fcx.tcx, substs); // Don't check non-defaulted params, dependent defaults or preds with multiple params. if substituted_pred.references_error() || param_count.params.len() > 1 { continue; } // Avoid duplication of predicates that contain no parameters, for example. if !predicates.predicates.contains(&substituted_pred) { substituted_predicates.push(substituted_pred); </ins> } } <del> fn check_fn_or_method<'fcx, 'tcx>(&mut self, fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, span: Span, sig: ty::PolyFnSig<'tcx>, def_id: DefId, implied_bounds: &mut Vec<Ty<'tcx>>) { let sig = fcx.normalize_associated_types_in(span, &sig); let sig = fcx.tcx.liberate_late_bound_regions(def_id, &sig); for input_ty in sig.inputs() { fcx.register_wf_obligation(&input_ty, span, self.code.clone()); } implied_bounds.extend(sig.inputs()); </del> <ins> predicates.predicates.extend(substituted_predicates); let predicates = predicates.instantiate_identity(fcx.tcx); let predicates = fcx.normalize_associated_types_in(span, &predicates); let obligations = predicates.predicates .iter() .flat_map(|p| ty::wf::predicate_obligations(fcx, fcx.param_env, fcx.body_id, p, span)); for obligation in obligations { fcx.register_predicate(obligation); } } </ins> <del> fcx.register_wf_obligation(sig.output(), span, self.code.clone()); </del> <ins> fn check_fn_or_method<'a, 'fcx, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, span: Span, sig: ty::PolyFnSig<'tcx>, def_id: DefId, implied_bounds: &mut Vec<Ty<'tcx>>) { let sig = fcx.normalize_associated_types_in(span, &sig); let sig = fcx.tcx.liberate_late_bound_regions(def_id, &sig); for input_ty in sig.inputs() { fcx.register_wf_obligation(&input_ty, span, ObligationCauseCode::MiscObligation); } implied_bounds.extend(sig.inputs()); </ins> <del> // FIXME(#25759) return types should not be implied bounds implied_bounds.push(sig.output()); </del> <ins> fcx.register_wf_obligation(sig.output(), span, ObligationCauseCode::MiscObligation); </ins> <del> self.check_where_clauses(fcx, span, def_id); } </del> <ins> // FIXME(#25759) return types should not be implied bounds implied_bounds.push(sig.output()); </ins> <del> fn check_method_receiver<'fcx, 'tcx>(&mut self, fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, method_sig: &hir::MethodSig, method: &ty::AssociatedItem, self_ty: Ty<'tcx>) { // check that the method has a valid receiver type, given the type `Self` debug!("check_method_receiver({:?}, self_ty={:?})", method, self_ty); </del> <ins> check_where_clauses(tcx, fcx, span, def_id); } </ins> <del> if !method.method_has_self_argument { return; } </del> <ins> fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, method_sig: &hir::MethodSig, method: &ty::AssociatedItem, self_ty: Ty<'tcx>) { // check that the method has a valid receiver type, given the type `Self` debug!("check_method_receiver({:?}, self_ty={:?})", method, self_ty); if !method.method_has_self_argument { return; } </ins> <del> let span = method_sig.decl.inputs[0].span; </del> <ins> let span = method_sig.decl.inputs[0].span; </ins> <del> let sig = fcx.tcx.fn_sig(method.def_id); let sig = fcx.normalize_associated_types_in(span, &sig); let sig = fcx.tcx.liberate_late_bound_regions(method.def_id, &sig); </del> <ins> let sig = fcx.tcx.fn_sig(method.def_id); let sig = fcx.normalize_associated_types_in(span, &sig); let sig = fcx.tcx.liberate_late_bound_regions(method.def_id, &sig); </ins> <del> debug!("check_method_receiver: sig={:?}", sig); </del> <ins> debug!("check_method_receiver: sig={:?}", sig); </ins> <del> let self_ty = fcx.normalize_associated_types_in(span, &self_ty); let self_ty = fcx.tcx.liberate_late_bound_regions( method.def_id, &ty::Binder(self_ty) ); </del> <ins> let self_ty = fcx.normalize_associated_types_in(span, &self_ty); let self_ty = fcx.tcx.liberate_late_bound_regions( method.def_id, &ty::Binder(self_ty) ); </ins> <del> let self_arg_ty = sig.inputs()[0]; </del> <ins> let self_arg_ty = sig.inputs()[0]; </ins> <del> let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver); let self_arg_ty = fcx.normalize_associated_types_in(span, &self_arg_ty); let self_arg_ty = fcx.tcx.liberate_late_bound_regions( method.def_id, &ty::Binder(self_arg_ty) ); </del> <ins> let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver); let self_arg_ty = fcx.normalize_associated_types_in(span, &self_arg_ty); let self_arg_ty = fcx.tcx.liberate_late_bound_regions( method.def_id, &ty::Binder(self_arg_ty) ); </ins> <del> let mut autoderef = fcx.autoderef(span, self_arg_ty).include_raw_pointers(); </del> <ins> let mut autoderef = fcx.autoderef(span, self_arg_ty).include_raw_pointers(); </ins> <del> loop { if let Some((potential_self_ty, _)) = autoderef.next() { debug!("check_method_receiver: potential self type `{:?}` to match `{:?}`", potential_self_ty, self_ty); </del> <ins> loop { if let Some((potential_self_ty, _)) = autoderef.next() { debug!("check_method_receiver: potential self type `{:?}` to match `{:?}`", potential_self_ty, self_ty); </ins> <del> if fcx.infcx.can_eq(fcx.param_env, self_ty, potential_self_ty).is_ok() { autoderef.finalize(); if let Some(mut err) = fcx.demand_eqtype_with_origin( &cause, self_ty, potential_self_ty) { err.emit(); } break </del> <ins> if fcx.infcx.can_eq(fcx.param_env, self_ty, potential_self_ty).is_ok() { autoderef.finalize(); if let Some(mut err) = fcx.demand_eqtype_with_origin( &cause, self_ty, potential_self_ty) { err.emit(); </ins> } <del> } else { fcx.tcx.sess.diagnostic().mut_span_err( span, &format!("invalid `self` type: {:?}", self_arg_ty)) .note(&format!("type must be `{:?}` or a type that dereferences to it", self_ty)) .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`") .code(DiagnosticId::Error("E0307".into())) .emit(); return </del> <ins> break </ins> } <ins> } else { fcx.tcx.sess.diagnostic().mut_span_err( span, &format!("invalid `self` type: {:?}", self_arg_ty)) .note(&format!("type must be `{:?}` or a type that dereferences to it", self_ty)) .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`") .code(DiagnosticId::Error("E0307".into())) .emit(); return </ins> } <ins> } </ins> <del> let is_self_ty = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok(); let self_kind = ExplicitSelf::determine(self_arg_ty, is_self_ty); if !fcx.tcx.features().arbitrary_self_types { match self_kind { ExplicitSelf::ByValue | ExplicitSelf::ByReference(_, _) | ExplicitSelf::ByBox => (), ExplicitSelf::ByRawPointer(_) => { feature_gate::feature_err( &fcx.tcx.sess.parse_sess, "arbitrary_self_types", span, GateIssue::Language, "raw pointer `self` is unstable") .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`") .emit(); } </del> <ins> let is_self_ty = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok(); let self_kind = ExplicitSelf::determine(self_arg_ty, is_self_ty); if !fcx.tcx.features().arbitrary_self_types { match self_kind { ExplicitSelf::ByValue | ExplicitSelf::ByReference(_, _) | ExplicitSelf::ByBox => (), ExplicitSelf::ByRawPointer(_) => { feature_gate::feature_err( &fcx.tcx.sess.parse_sess, "arbitrary_self_types", span, GateIssue::Language, "raw pointer `self` is unstable") .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`") .emit(); } </ins> <del> ExplicitSelf::Other => { feature_gate::feature_err( &fcx.tcx.sess.parse_sess, "arbitrary_self_types", span, GateIssue::Language,"arbitrary `self` types are unstable") .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`") .emit(); } </del> <ins> ExplicitSelf::Other => { feature_gate::feature_err( &fcx.tcx.sess.parse_sess, "arbitrary_self_types", span, GateIssue::Language,"arbitrary `self` types are unstable") .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`") .emit(); </ins> } } } <ins> } </ins> <del> fn check_variances_for_type_defn(&self, item: &hir::Item, ast_generics: &hir::Generics) { let item_def_id = self.tcx.hir.local_def_id(item.id); let ty = self.tcx.type_of(item_def_id); if self.tcx.has_error_field(ty) { return; } let ty_predicates = self.tcx.predicates_of(item_def_id); assert_eq!(ty_predicates.parent, None); let variances = self.tcx.variances_of(item_def_id); </del> <ins> fn check_variances_for_type_defn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item, ast_generics: &hir::Generics) { let item_def_id = tcx.hir.local_def_id(item.id); let ty = tcx.type_of(item_def_id); if tcx.has_error_field(ty) { return; } </ins> <del> let mut constrained_parameters: FxHashSet<_> = variances.iter().enumerate() .filter(|&(_, &variance)| variance != ty::Bivariant) .map(|(index, _)| Parameter(index as u32)) .collect(); </del> <ins> let ty_predicates = tcx.predicates_of(item_def_id); assert_eq!(ty_predicates.parent, None); let variances = tcx.variances_of(item_def_id); </ins> <del> identify_constrained_type_params(self.tcx, ty_predicates.predicates.as_slice(), None, &mut constrained_parameters); </del> <ins> let mut constrained_parameters: FxHashSet<_> = variances.iter().enumerate() .filter(|&(_, &variance)| variance != ty::Bivariant) .map(|(index, _)| Parameter(index as u32)) .collect(); </ins> <del> for (index, _) in variances.iter().enumerate() { if constrained_parameters.contains(&Parameter(index as u32)) { continue; } </del> <ins> identify_constrained_type_params(tcx, ty_predicates.predicates.as_slice(), None, &mut constrained_parameters); </ins> <del> let (span, name) = match ast_generics.params[index] { hir::GenericParam::Lifetime(ref ld) => (ld.lifetime.span, ld.lifetime.name.name()), hir::GenericParam::Type(ref tp) => (tp.span, tp.name), }; self.report_bivariance(span, name); </del> <ins> for (index, _) in variances.iter().enumerate() { if constrained_parameters.contains(&Parameter(index as u32)) { continue; </ins> } <ins> let (span, name) = match ast_generics.params[index] { hir::GenericParam::Lifetime(ref ld) => (ld.lifetime.span, ld.lifetime.name.name()), hir::GenericParam::Type(ref tp) => (tp.span, tp.name), }; report_bivariance(tcx, span, name); </ins> } <ins> } </ins> <del> fn report_bivariance(&self, span: Span, param_name: ast::Name) { let mut err = error_392(self.tcx, span, param_name); let suggested_marker_id = self.tcx.lang_items().phantom_data(); match suggested_marker_id { Some(def_id) => { err.help( &format!("consider removing `{}` or using a marker such as `{}`", param_name, self.tcx.item_path_str(def_id))); } None => { // no lang items, no help! } </del> <ins> fn report_bivariance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, param_name: ast::Name) { let mut err = error_392(tcx, span, param_name); let suggested_marker_id = tcx.lang_items().phantom_data(); match suggested_marker_id { Some(def_id) => { err.help( &format!("consider removing `{}` or using a marker such as `{}`", param_name, tcx.item_path_str(def_id))); } None => { // no lang items, no help! </ins> } <del> err.emit(); </del> } <ins> err.emit(); </ins> } fn reject_shadowing_type_parameters(tcx: TyCtxt, def_id: DefId) {

} } <ins> pub struct CheckTypeWellFormedVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, } impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { pub fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>) -> CheckTypeWellFormedVisitor<'a, 'gcx> { CheckTypeWellFormedVisitor { tcx, } } } </ins> impl<'a, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'a, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> { NestedVisitorMap::None

fn visit_item(&mut self, i: &hir::Item) { debug!("visit_item: {:?}", i); <del> self.check_item_well_formed(i); </del> <ins> let def_id = self.tcx.hir.local_def_id(i.id); ty::maps::queries::check_item_well_formed::ensure(self.tcx, def_id); </ins> intravisit::walk_item(self, i); } fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) { debug!("visit_trait_item: {:?}", trait_item); <del> let method_sig = match trait_item.node { hir::TraitItemKind::Method(ref sig, _) => Some(sig), _ => None }; self.check_associated_item(trait_item.id, trait_item.span, method_sig); </del> <ins> let def_id = self.tcx.hir.local_def_id(trait_item.id); ty::maps::queries::check_trait_item_well_formed::ensure(self.tcx, def_id); </ins> intravisit::walk_trait_item(self, trait_item) } fn visit_impl_item(&mut self, impl_item: &'v hir::ImplItem) { debug!("visit_impl_item: {:?}", impl_item); <del> let method_sig = match impl_item.node { hir::ImplItemKind::Method(ref sig, _) => Some(sig), _ => None }; self.check_associated_item(impl_item.id, impl_item.span, method_sig); </del> <ins> let def_id = self.tcx.hir.local_def_id(impl_item.id); ty::maps::queries::check_impl_item_well_formed::ensure(self.tcx, def_id); </ins> intravisit::walk_impl_item(self, impl_item) } }