From 47256b8b7c78f188defaed8f5491ce01812622b1 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jan 2020 15:31:56 +0100 Subject: [PATCH 01/18] Remove private methods from TyCtxt impl block: rustc::infer::error_reporting. --- src/librustc/infer/error_reporting/mod.rs | 214 +++++++++--------- .../nice_region_error/static_impl_trait.rs | 3 +- 2 files changed, 109 insertions(+), 108 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 90f546113c1bc..e653f645881f8 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -107,9 +107,9 @@ impl<'tcx> TyCtxt<'tcx> { _ => "expression", }, Some(Node::Stmt(_)) => "statement", - Some(Node::Item(it)) => Self::item_scope_tag(&it), - Some(Node::TraitItem(it)) => Self::trait_item_scope_tag(&it), - Some(Node::ImplItem(it)) => Self::impl_item_scope_tag(&it), + Some(Node::Item(it)) => item_scope_tag(&it), + Some(Node::TraitItem(it)) => trait_item_scope_tag(&it), + Some(Node::ImplItem(it)) => impl_item_scope_tag(&it), Some(_) | None => { err.span_note(span, &unknown_scope()); return; @@ -131,11 +131,11 @@ impl<'tcx> TyCtxt<'tcx> { &new_string[..] } }; - self.explain_span(scope_decorated_tag, span) + explain_span(self, scope_decorated_tag, span) } ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => { - self.msg_span_from_free_region(region) + msg_span_from_free_region(self, region) } ty::ReEmpty => ("the empty lifetime".to_owned(), None), @@ -157,7 +157,7 @@ impl<'tcx> TyCtxt<'tcx> { } }; - TyCtxt::emit_msg_span(err, prefix, description, span, suffix); + emit_msg_span(err, prefix, description, span, suffix); } pub fn note_and_explain_free_region( @@ -167,124 +167,124 @@ impl<'tcx> TyCtxt<'tcx> { region: ty::Region<'tcx>, suffix: &str, ) { - let (description, span) = self.msg_span_from_free_region(region); + let (description, span) = msg_span_from_free_region(self, region); - TyCtxt::emit_msg_span(err, prefix, description, span, suffix); + emit_msg_span(err, prefix, description, span, suffix); } +} - fn msg_span_from_free_region(self, region: ty::Region<'tcx>) -> (String, Option) { - match *region { - ty::ReEarlyBound(_) | ty::ReFree(_) => { - self.msg_span_from_early_bound_and_free_regions(region) - } - ty::ReStatic => ("the static lifetime".to_owned(), None), - ty::ReEmpty => ("an empty lifetime".to_owned(), None), - _ => bug!("{:?}", region), +fn msg_span_from_free_region( + tcx: TyCtxt<'tcx>, + region: ty::Region<'tcx>, +) -> (String, Option) { + match *region { + ty::ReEarlyBound(_) | ty::ReFree(_) => { + msg_span_from_early_bound_and_free_regions(tcx, region) } + ty::ReStatic => ("the static lifetime".to_owned(), None), + ty::ReEmpty => ("an empty lifetime".to_owned(), None), + _ => bug!("{:?}", region), } +} - fn msg_span_from_early_bound_and_free_regions( - self, - region: ty::Region<'tcx>, - ) -> (String, Option) { - let cm = self.sess.source_map(); - - let scope = region.free_region_binding_scope(self); - let node = self.hir().as_local_hir_id(scope).unwrap_or(hir::DUMMY_HIR_ID); - let tag = match self.hir().find(node) { - Some(Node::Block(_)) | Some(Node::Expr(_)) => "body", - Some(Node::Item(it)) => Self::item_scope_tag(&it), - Some(Node::TraitItem(it)) => Self::trait_item_scope_tag(&it), - Some(Node::ImplItem(it)) => Self::impl_item_scope_tag(&it), - _ => unreachable!(), - }; - let (prefix, span) = match *region { - ty::ReEarlyBound(ref br) => { - let mut sp = cm.def_span(self.hir().span(node)); - if let Some(param) = - self.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) - { - sp = param.span; - } - (format!("the lifetime `{}` as defined on", br.name), sp) - } - ty::ReFree(ty::FreeRegion { - bound_region: ty::BoundRegion::BrNamed(_, name), .. - }) => { - let mut sp = cm.def_span(self.hir().span(node)); - if let Some(param) = - self.hir().get_generics(scope).and_then(|generics| generics.get_named(name)) - { - sp = param.span; - } - (format!("the lifetime `{}` as defined on", name), sp) - } - ty::ReFree(ref fr) => match fr.bound_region { - ty::BrAnon(idx) => ( - format!("the anonymous lifetime #{} defined on", idx + 1), - self.hir().span(node), - ), - _ => ( - format!("the lifetime `{}` as defined on", region), - cm.def_span(self.hir().span(node)), - ), - }, - _ => bug!(), - }; - let (msg, opt_span) = self.explain_span(tag, span); - (format!("{} {}", prefix, msg), opt_span) - } - - fn emit_msg_span( - err: &mut DiagnosticBuilder<'_>, - prefix: &str, - description: String, - span: Option, - suffix: &str, - ) { - let message = format!("{}{}{}", prefix, description, suffix); - - if let Some(span) = span { - err.span_note(span, &message); - } else { - err.note(&message); +fn msg_span_from_early_bound_and_free_regions( + tcx: TyCtxt<'tcx>, + region: ty::Region<'tcx>, +) -> (String, Option) { + let cm = tcx.sess.source_map(); + + let scope = region.free_region_binding_scope(tcx); + let node = tcx.hir().as_local_hir_id(scope).unwrap_or(hir::DUMMY_HIR_ID); + let tag = match tcx.hir().find(node) { + Some(Node::Block(_)) | Some(Node::Expr(_)) => "body", + Some(Node::Item(it)) => item_scope_tag(&it), + Some(Node::TraitItem(it)) => trait_item_scope_tag(&it), + Some(Node::ImplItem(it)) => impl_item_scope_tag(&it), + _ => unreachable!(), + }; + let (prefix, span) = match *region { + ty::ReEarlyBound(ref br) => { + let mut sp = cm.def_span(tcx.hir().span(node)); + if let Some(param) = + tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) + { + sp = param.span; + } + (format!("the lifetime `{}` as defined on", br.name), sp) } - } - - fn item_scope_tag(item: &hir::Item<'_>) -> &'static str { - match item.kind { - hir::ItemKind::Impl(..) => "impl", - hir::ItemKind::Struct(..) => "struct", - hir::ItemKind::Union(..) => "union", - hir::ItemKind::Enum(..) => "enum", - hir::ItemKind::Trait(..) => "trait", - hir::ItemKind::Fn(..) => "function body", - _ => "item", + ty::ReFree(ty::FreeRegion { bound_region: ty::BoundRegion::BrNamed(_, name), .. }) => { + let mut sp = cm.def_span(tcx.hir().span(node)); + if let Some(param) = + tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name)) + { + sp = param.span; + } + (format!("the lifetime `{}` as defined on", name), sp) } + ty::ReFree(ref fr) => match fr.bound_region { + ty::BrAnon(idx) => { + (format!("the anonymous lifetime #{} defined on", idx + 1), tcx.hir().span(node)) + } + _ => ( + format!("the lifetime `{}` as defined on", region), + cm.def_span(tcx.hir().span(node)), + ), + }, + _ => bug!(), + }; + let (msg, opt_span) = explain_span(tcx, tag, span); + (format!("{} {}", prefix, msg), opt_span) +} + +fn emit_msg_span( + err: &mut DiagnosticBuilder<'_>, + prefix: &str, + description: String, + span: Option, + suffix: &str, +) { + let message = format!("{}{}{}", prefix, description, suffix); + + if let Some(span) = span { + err.span_note(span, &message); + } else { + err.note(&message); } +} - fn trait_item_scope_tag(item: &hir::TraitItem<'_>) -> &'static str { - match item.kind { - hir::TraitItemKind::Method(..) => "method body", - hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => "associated item", - } +fn item_scope_tag(item: &hir::Item<'_>) -> &'static str { + match item.kind { + hir::ItemKind::Impl(..) => "impl", + hir::ItemKind::Struct(..) => "struct", + hir::ItemKind::Union(..) => "union", + hir::ItemKind::Enum(..) => "enum", + hir::ItemKind::Trait(..) => "trait", + hir::ItemKind::Fn(..) => "function body", + _ => "item", } +} - fn impl_item_scope_tag(item: &hir::ImplItem<'_>) -> &'static str { - match item.kind { - hir::ImplItemKind::Method(..) => "method body", - hir::ImplItemKind::Const(..) - | hir::ImplItemKind::OpaqueTy(..) - | hir::ImplItemKind::TyAlias(..) => "associated item", - } +fn trait_item_scope_tag(item: &hir::TraitItem<'_>) -> &'static str { + match item.kind { + hir::TraitItemKind::Method(..) => "method body", + hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => "associated item", } +} - fn explain_span(self, heading: &str, span: Span) -> (String, Option) { - let lo = self.sess.source_map().lookup_char_pos(span.lo()); - (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), Some(span)) +fn impl_item_scope_tag(item: &hir::ImplItem<'_>) -> &'static str { + match item.kind { + hir::ImplItemKind::Method(..) => "method body", + hir::ImplItemKind::Const(..) + | hir::ImplItemKind::OpaqueTy(..) + | hir::ImplItemKind::TyAlias(..) => "associated item", } } +fn explain_span(tcx: TyCtxt<'tcx>, heading: &str, span: Span) -> (String, Option) { + let lo = tcx.sess.source_map().lookup_char_pos(span.lo()); + (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), Some(span)) +} + impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn report_region_errors( &self, diff --git a/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs index 69ebbe1fd3679..6c78e70a4444d 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -1,5 +1,6 @@ //! Error Reporting for static impl Traits. +use crate::infer::error_reporting::msg_span_from_free_region; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::ty::{BoundRegion, FreeRegion, RegionKind}; @@ -32,7 +33,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ); err.span_label(sup_origin.span(), "...but this borrow..."); - let (lifetime, lt_sp_opt) = self.tcx().msg_span_from_free_region(sup_r); + let (lifetime, lt_sp_opt) = msg_span_from_free_region(self.tcx(), sup_r); if let Some(lifetime_sp) = lt_sp_opt { err.span_note(lifetime_sp, &format!("...can't outlive {}", lifetime)); } From 811adb5ddc539e0084c9311f14004daec0e34d0f Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jan 2020 15:34:45 +0100 Subject: [PATCH 02/18] Remove private methods from TyCtxt impl block: rustc::middle::stability. --- src/librustc/middle/stability.rs | 48 +++++++++++++++----------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index a29b1b48c24f9..f2474faa75e44 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -245,35 +245,35 @@ pub enum EvalResult { Unmarked, } -impl<'tcx> TyCtxt<'tcx> { - // See issue #38412. - fn skip_stability_check_due_to_privacy(self, mut def_id: DefId) -> bool { - // Check if `def_id` is a trait method. - match self.def_kind(def_id) { - Some(DefKind::Method) | Some(DefKind::AssocTy) | Some(DefKind::AssocConst) => { - if let ty::TraitContainer(trait_def_id) = self.associated_item(def_id).container { - // Trait methods do not declare visibility (even - // for visibility info in cstore). Use containing - // trait instead, so methods of `pub` traits are - // themselves considered `pub`. - def_id = trait_def_id; - } +// See issue #38412. +fn skip_stability_check_due_to_privacy(tcx: TyCtxt<'_>, mut def_id: DefId) -> bool { + // Check if `def_id` is a trait method. + match tcx.def_kind(def_id) { + Some(DefKind::Method) | Some(DefKind::AssocTy) | Some(DefKind::AssocConst) => { + if let ty::TraitContainer(trait_def_id) = tcx.associated_item(def_id).container { + // Trait methods do not declare visibility (even + // for visibility info in cstore). Use containing + // trait instead, so methods of `pub` traits are + // themselves considered `pub`. + def_id = trait_def_id; } - _ => {} } + _ => {} + } - let visibility = self.visibility(def_id); + let visibility = tcx.visibility(def_id); - match visibility { - // Must check stability for `pub` items. - ty::Visibility::Public => false, + match visibility { + // Must check stability for `pub` items. + ty::Visibility::Public => false, - // These are not visible outside crate; therefore - // stability markers are irrelevant, if even present. - ty::Visibility::Restricted(..) | ty::Visibility::Invisible => true, - } + // These are not visible outside crate; therefore + // stability markers are irrelevant, if even present. + ty::Visibility::Restricted(..) | ty::Visibility::Invisible => true, } +} +impl<'tcx> TyCtxt<'tcx> { /// Evaluates the stability of an item. /// /// Returns `EvalResult::Allow` if the item is stable, or unstable but the corresponding @@ -338,7 +338,7 @@ impl<'tcx> TyCtxt<'tcx> { } // Issue #38412: private items lack stability markers. - if self.skip_stability_check_due_to_privacy(def_id) { + if skip_stability_check_due_to_privacy(self, def_id) { return EvalResult::Allow; } @@ -402,9 +402,7 @@ impl<'tcx> TyCtxt<'tcx> { } } } -} -impl<'tcx> TyCtxt<'tcx> { pub fn lookup_deprecation(self, id: DefId) -> Option { self.lookup_deprecation_entry(id).map(|depr| depr.attr) } From c1afe6a9c9f8339134513857dd26dccb20df88d2 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jan 2020 15:48:46 +0100 Subject: [PATCH 03/18] Remove private methods from TyCtxt impl block: rustc::trait::object_safety. --- src/librustc/traits/object_safety.rs | 1009 +++++++++++++------------- 1 file changed, 508 insertions(+), 501 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 836e67cff8b2c..3c64a46661d05 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -119,7 +119,7 @@ impl<'tcx> TyCtxt<'tcx> { ) -> Vec { debug_assert!(self.generics_of(trait_def_id).has_self); let violations = traits::supertrait_def_ids(self, trait_def_id) - .filter(|&def_id| self.predicates_reference_self(def_id, true)) + .filter(|&def_id| predicates_reference_self(self, def_id, true)) .map(|_| ObjectSafetyViolation::SupertraitSelf) .collect(); @@ -136,7 +136,7 @@ impl<'tcx> TyCtxt<'tcx> { debug!("object_safety_violations: {:?}", trait_def_id); traits::supertrait_def_ids(self, trait_def_id) - .flat_map(|def_id| self.object_safety_violations_for_trait(def_id)) + .flat_map(|def_id| object_safety_violations_for_trait(self, def_id)) .collect() } @@ -148,572 +148,579 @@ impl<'tcx> TyCtxt<'tcx> { debug_assert!(self.generics_of(trait_def_id).has_self); debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method); // Any method that has a `Self: Sized` bound cannot be called. - if self.generics_require_sized_self(method.def_id) { + if generics_require_sized_self(self, method.def_id) { return false; } - match self.virtual_call_violation_for_method(trait_def_id, method) { + match virtual_call_violation_for_method(self, trait_def_id, method) { None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true, Some(_) => false, } } +} - fn object_safety_violations_for_trait(self, trait_def_id: DefId) -> Vec { - // Check methods for violations. - let mut violations: Vec<_> = self - .associated_items(trait_def_id) - .filter(|item| item.kind == ty::AssocKind::Method) - .filter_map(|item| { - self.object_safety_violation_for_method(trait_def_id, &item).map(|code| { - ObjectSafetyViolation::Method(item.ident.name, code, item.ident.span) - }) - }) - .filter(|violation| { - if let ObjectSafetyViolation::Method( - _, - MethodViolationCode::WhereClauseReferencesSelf, - span, - ) = violation - { - // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id. - // It's also hard to get a use site span, so we use the method definition span. - self.lint_node_note( - lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY, - hir::CRATE_HIR_ID, - *span, - &format!( - "the trait `{}` cannot be made into an object", - self.def_path_str(trait_def_id) - ), - &violation.error_msg(), - ); - false - } else { - true - } - }) - .collect(); - - // Check the trait itself. - if self.trait_has_sized_self(trait_def_id) { - violations.push(ObjectSafetyViolation::SizedSelf); - } - if self.predicates_reference_self(trait_def_id, false) { - violations.push(ObjectSafetyViolation::SupertraitSelf); - } - - violations.extend( - self.associated_items(trait_def_id) - .filter(|item| item.kind == ty::AssocKind::Const) - .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)), - ); - - debug!( - "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", - trait_def_id, violations - ); +fn object_safety_violations_for_trait( + tcx: TyCtxt<'_>, + trait_def_id: DefId, +) -> Vec { + // Check methods for violations. + let mut violations: Vec<_> = tcx + .associated_items(trait_def_id) + .filter(|item| item.kind == ty::AssocKind::Method) + .filter_map(|item| { + object_safety_violation_for_method(tcx, trait_def_id, &item) + .map(|code| ObjectSafetyViolation::Method(item.ident.name, code, item.ident.span)) + }) + .filter(|violation| { + if let ObjectSafetyViolation::Method( + _, + MethodViolationCode::WhereClauseReferencesSelf, + span, + ) = violation + { + // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id. + // It's also hard to get a use site span, so we use the method definition span. + tcx.lint_node_note( + lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY, + hir::CRATE_HIR_ID, + *span, + &format!( + "the trait `{}` cannot be made into an object", + tcx.def_path_str(trait_def_id) + ), + &violation.error_msg(), + ); + false + } else { + true + } + }) + .collect(); - violations + // Check the trait itself. + if trait_has_sized_self(tcx, trait_def_id) { + violations.push(ObjectSafetyViolation::SizedSelf); } - - fn predicates_reference_self(self, trait_def_id: DefId, supertraits_only: bool) -> bool { - let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(self, trait_def_id)); - let predicates = if supertraits_only { - self.super_predicates_of(trait_def_id) - } else { - self.predicates_of(trait_def_id) - }; - let self_ty = self.types.self_param; - let has_self_ty = |t: Ty<'tcx>| t.walk().any(|t| t == self_ty); - predicates - .predicates - .iter() - .map(|(predicate, _)| predicate.subst_supertrait(self, &trait_ref)) - .any(|predicate| { - match predicate { - ty::Predicate::Trait(ref data) => { - // In the case of a trait predicate, we can skip the "self" type. - data.skip_binder().input_types().skip(1).any(has_self_ty) - } - ty::Predicate::Projection(ref data) => { - // And similarly for projections. This should be redundant with - // the previous check because any projection should have a - // matching `Trait` predicate with the same inputs, but we do - // the check to be safe. - // - // Note that we *do* allow projection *outputs* to contain - // `self` (i.e., `trait Foo: Bar { type Result; }`), - // we just require the user to specify *both* outputs - // in the object type (i.e., `dyn Foo`). - // - // This is ALT2 in issue #56288, see that for discussion of the - // possible alternatives. - data.skip_binder() - .projection_ty - .trait_ref(self) - .input_types() - .skip(1) - .any(has_self_ty) - } - ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::TypeOutlives(..) - | ty::Predicate::RegionOutlives(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::ConstEvaluatable(..) => false, - } - }) + if predicates_reference_self(tcx, trait_def_id, false) { + violations.push(ObjectSafetyViolation::SupertraitSelf); } - fn trait_has_sized_self(self, trait_def_id: DefId) -> bool { - self.generics_require_sized_self(trait_def_id) - } + violations.extend( + tcx.associated_items(trait_def_id) + .filter(|item| item.kind == ty::AssocKind::Const) + .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)), + ); - fn generics_require_sized_self(self, def_id: DefId) -> bool { - let sized_def_id = match self.lang_items().sized_trait() { - Some(def_id) => def_id, - None => { - return false; /* No Sized trait, can't require it! */ - } - }; + debug!( + "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", + trait_def_id, violations + ); - // Search for a predicate like `Self : Sized` amongst the trait bounds. - let predicates = self.predicates_of(def_id); - let predicates = predicates.instantiate_identity(self).predicates; - elaborate_predicates(self, predicates).any(|predicate| match predicate { - ty::Predicate::Trait(ref trait_pred) => { - trait_pred.def_id() == sized_def_id - && trait_pred.skip_binder().self_ty().is_param(0) + violations +} + +fn predicates_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId, supertraits_only: bool) -> bool { + let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id)); + let predicates = if supertraits_only { + tcx.super_predicates_of(trait_def_id) + } else { + tcx.predicates_of(trait_def_id) + }; + let self_ty = tcx.types.self_param; + let has_self_ty = |t: Ty<'_>| t.walk().any(|t| t == self_ty); + predicates + .predicates + .iter() + .map(|(predicate, _)| predicate.subst_supertrait(tcx, &trait_ref)) + .any(|predicate| { + match predicate { + ty::Predicate::Trait(ref data) => { + // In the case of a trait predicate, we can skip the "self" type. + data.skip_binder().input_types().skip(1).any(has_self_ty) + } + ty::Predicate::Projection(ref data) => { + // And similarly for projections. This should be redundant with + // the previous check because any projection should have a + // matching `Trait` predicate with the same inputs, but we do + // the check to be safe. + // + // Note that we *do* allow projection *outputs* to contain + // `self` (i.e., `trait Foo: Bar { type Result; }`), + // we just require the user to specify *both* outputs + // in the object type (i.e., `dyn Foo`). + // + // This is ALT2 in issue #56288, see that for discussion of the + // possible alternatives. + data.skip_binder() + .projection_ty + .trait_ref(tcx) + .input_types() + .skip(1) + .any(has_self_ty) + } + ty::Predicate::WellFormed(..) + | ty::Predicate::ObjectSafe(..) + | ty::Predicate::TypeOutlives(..) + | ty::Predicate::RegionOutlives(..) + | ty::Predicate::ClosureKind(..) + | ty::Predicate::Subtype(..) + | ty::Predicate::ConstEvaluatable(..) => false, } - ty::Predicate::Projection(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::RegionOutlives(..) - | ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::TypeOutlives(..) - | ty::Predicate::ConstEvaluatable(..) => false, }) - } +} - /// Returns `Some(_)` if this method makes the containing trait not object safe. - fn object_safety_violation_for_method( - self, - trait_def_id: DefId, - method: &ty::AssocItem, - ) -> Option { - debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method); - // Any method that has a `Self : Sized` requisite is otherwise - // exempt from the regulations. - if self.generics_require_sized_self(method.def_id) { - return None; +fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { + generics_require_sized_self(tcx, trait_def_id) +} + +fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + let sized_def_id = match tcx.lang_items().sized_trait() { + Some(def_id) => def_id, + None => { + return false; /* No Sized trait, can't require it! */ + } + }; + + // Search for a predicate like `Self : Sized` amongst the trait bounds. + let predicates = tcx.predicates_of(def_id); + let predicates = predicates.instantiate_identity(tcx).predicates; + elaborate_predicates(tcx, predicates).any(|predicate| match predicate { + ty::Predicate::Trait(ref trait_pred) => { + trait_pred.def_id() == sized_def_id && trait_pred.skip_binder().self_ty().is_param(0) } + ty::Predicate::Projection(..) + | ty::Predicate::Subtype(..) + | ty::Predicate::RegionOutlives(..) + | ty::Predicate::WellFormed(..) + | ty::Predicate::ObjectSafe(..) + | ty::Predicate::ClosureKind(..) + | ty::Predicate::TypeOutlives(..) + | ty::Predicate::ConstEvaluatable(..) => false, + }) +} - self.virtual_call_violation_for_method(trait_def_id, method) +/// Returns `Some(_)` if this method makes the containing trait not object safe. +fn object_safety_violation_for_method( + tcx: TyCtxt<'_>, + trait_def_id: DefId, + method: &ty::AssocItem, +) -> Option { + debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method); + // Any method that has a `Self : Sized` requisite is otherwise + // exempt from the regulations. + if generics_require_sized_self(tcx, method.def_id) { + return None; } - /// Returns `Some(_)` if this method cannot be called on a trait - /// object; this does not necessarily imply that the enclosing trait - /// is not object safe, because the method might have a where clause - /// `Self:Sized`. - fn virtual_call_violation_for_method( - self, - trait_def_id: DefId, - method: &ty::AssocItem, - ) -> Option { - // The method's first parameter must be named `self` - if !method.method_has_self_argument { - return Some(MethodViolationCode::StaticMethod); - } + virtual_call_violation_for_method(tcx, trait_def_id, method) +} - let sig = self.fn_sig(method.def_id); +/// Returns `Some(_)` if this method cannot be called on a trait +/// object; this does not necessarily imply that the enclosing trait +/// is not object safe, because the method might have a where clause +/// `Self:Sized`. +fn virtual_call_violation_for_method<'tcx>( + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + method: &ty::AssocItem, +) -> Option { + // The method's first parameter must be named `self` + if !method.method_has_self_argument { + return Some(MethodViolationCode::StaticMethod); + } - for input_ty in &sig.skip_binder().inputs()[1..] { - if self.contains_illegal_self_type_reference(trait_def_id, input_ty) { - return Some(MethodViolationCode::ReferencesSelf); - } - } - if self.contains_illegal_self_type_reference(trait_def_id, sig.output().skip_binder()) { + let sig = tcx.fn_sig(method.def_id); + + for input_ty in &sig.skip_binder().inputs()[1..] { + if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) { return Some(MethodViolationCode::ReferencesSelf); } + } + if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output().skip_binder()) { + return Some(MethodViolationCode::ReferencesSelf); + } - // We can't monomorphize things like `fn foo(...)`. - let own_counts = self.generics_of(method.def_id).own_counts(); - if own_counts.types + own_counts.consts != 0 { - return Some(MethodViolationCode::Generic); - } + // We can't monomorphize things like `fn foo(...)`. + let own_counts = tcx.generics_of(method.def_id).own_counts(); + if own_counts.types + own_counts.consts != 0 { + return Some(MethodViolationCode::Generic); + } - if self - .predicates_of(method.def_id) - .predicates - .iter() - // A trait object can't claim to live more than the concrete type, - // so outlives predicates will always hold. - .cloned() - .filter(|(p, _)| p.to_opt_type_outlives().is_none()) - .collect::>() - // Do a shallow visit so that `contains_illegal_self_type_reference` - // may apply it's custom visiting. - .visit_tys_shallow(|t| self.contains_illegal_self_type_reference(trait_def_id, t)) - { - return Some(MethodViolationCode::WhereClauseReferencesSelf); - } + if tcx + .predicates_of(method.def_id) + .predicates + .iter() + // A trait object can't claim to live more than the concrete type, + // so outlives predicates will always hold. + .cloned() + .filter(|(p, _)| p.to_opt_type_outlives().is_none()) + .collect::>() + // Do a shallow visit so that `contains_illegal_self_type_reference` + // may apply it's custom visiting. + .visit_tys_shallow(|t| contains_illegal_self_type_reference(tcx, trait_def_id, t)) + { + return Some(MethodViolationCode::WhereClauseReferencesSelf); + } - let receiver_ty = - self.liberate_late_bound_regions(method.def_id, &sig.map_bound(|sig| sig.inputs()[0])); + let receiver_ty = + tcx.liberate_late_bound_regions(method.def_id, &sig.map_bound(|sig| sig.inputs()[0])); - // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on. - // However, this is already considered object-safe. We allow it as a special case here. - // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows - // `Receiver: Unsize dyn Trait]>`. - if receiver_ty != self.types.self_param { - if !self.receiver_is_dispatchable(method, receiver_ty) { - return Some(MethodViolationCode::UndispatchableReceiver); - } else { - // Do sanity check to make sure the receiver actually has the layout of a pointer. + // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on. + // However, this is already considered object-safe. We allow it as a special case here. + // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows + // `Receiver: Unsize dyn Trait]>`. + if receiver_ty != tcx.types.self_param { + if !receiver_is_dispatchable(tcx, method, receiver_ty) { + return Some(MethodViolationCode::UndispatchableReceiver); + } else { + // Do sanity check to make sure the receiver actually has the layout of a pointer. - use crate::ty::layout::Abi; + use crate::ty::layout::Abi; - let param_env = self.param_env(method.def_id); + let param_env = tcx.param_env(method.def_id); - let abi_of_ty = |ty: Ty<'tcx>| -> &Abi { - match self.layout_of(param_env.and(ty)) { - Ok(layout) => &layout.abi, - Err(err) => { - bug!("error: {}\n while computing layout for type {:?}", err, ty) - } - } - }; - - // e.g., `Rc<()>` - let unit_receiver_ty = - self.receiver_for_self_ty(receiver_ty, self.mk_unit(), method.def_id); - - match abi_of_ty(unit_receiver_ty) { - &Abi::Scalar(..) => (), - abi => { - self.sess.delay_span_bug( - self.def_span(method.def_id), - &format!( - "receiver when `Self = ()` should have a Scalar ABI; found {:?}", - abi - ), - ); - } + let abi_of_ty = |ty: Ty<'tcx>| -> &Abi { + match tcx.layout_of(param_env.and(ty)) { + Ok(layout) => &layout.abi, + Err(err) => bug!("error: {}\n while computing layout for type {:?}", err, ty), + } + }; + + // e.g., `Rc<()>` + let unit_receiver_ty = + receiver_for_self_ty(tcx, receiver_ty, tcx.mk_unit(), method.def_id); + + match abi_of_ty(unit_receiver_ty) { + &Abi::Scalar(..) => (), + abi => { + tcx.sess.delay_span_bug( + tcx.def_span(method.def_id), + &format!( + "receiver when `Self = ()` should have a Scalar ABI; found {:?}", + abi + ), + ); } + } - let trait_object_ty = - self.object_ty_for_trait(trait_def_id, self.mk_region(ty::ReStatic)); + let trait_object_ty = + object_ty_for_trait(tcx, trait_def_id, tcx.mk_region(ty::ReStatic)); - // e.g., `Rc` - let trait_object_receiver = - self.receiver_for_self_ty(receiver_ty, trait_object_ty, method.def_id); + // e.g., `Rc` + let trait_object_receiver = + receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method.def_id); - match abi_of_ty(trait_object_receiver) { - &Abi::ScalarPair(..) => (), - abi => { - self.sess.delay_span_bug( - self.def_span(method.def_id), - &format!( - "receiver when `Self = {}` should have a ScalarPair ABI; \ + match abi_of_ty(trait_object_receiver) { + &Abi::ScalarPair(..) => (), + abi => { + tcx.sess.delay_span_bug( + tcx.def_span(method.def_id), + &format!( + "receiver when `Self = {}` should have a ScalarPair ABI; \ found {:?}", - trait_object_ty, abi - ), - ); - } + trait_object_ty, abi + ), + ); } } } - - None } - /// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`. - /// For example, for `receiver_ty = Rc` and `self_ty = Foo`, returns `Rc`. - fn receiver_for_self_ty( - self, - receiver_ty: Ty<'tcx>, - self_ty: Ty<'tcx>, - method_def_id: DefId, - ) -> Ty<'tcx> { - debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id); - let substs = InternalSubsts::for_item(self, method_def_id, |param, _| { - if param.index == 0 { self_ty.into() } else { self.mk_param_from_def(param) } - }); - - let result = receiver_ty.subst(self, substs); - debug!( - "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}", - receiver_ty, self_ty, method_def_id, result - ); - result - } + None +} - /// Creates the object type for the current trait. For example, - /// if the current trait is `Deref`, then this will be - /// `dyn Deref + 'static`. - fn object_ty_for_trait(self, trait_def_id: DefId, lifetime: ty::Region<'tcx>) -> Ty<'tcx> { - debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id); +/// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`. +/// For example, for `receiver_ty = Rc` and `self_ty = Foo`, returns `Rc`. +fn receiver_for_self_ty<'tcx>( + tcx: TyCtxt<'tcx>, + receiver_ty: Ty<'tcx>, + self_ty: Ty<'tcx>, + method_def_id: DefId, +) -> Ty<'tcx> { + debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id); + let substs = InternalSubsts::for_item(tcx, method_def_id, |param, _| { + if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) } + }); + + let result = receiver_ty.subst(tcx, substs); + debug!( + "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}", + receiver_ty, self_ty, method_def_id, result + ); + result +} - let trait_ref = ty::TraitRef::identity(self, trait_def_id); +/// Creates the object type for the current trait. For example, +/// if the current trait is `Deref`, then this will be +/// `dyn Deref + 'static`. +fn object_ty_for_trait<'tcx>( + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + lifetime: ty::Region<'tcx>, +) -> Ty<'tcx> { + debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id); - let trait_predicate = ty::ExistentialPredicate::Trait( - ty::ExistentialTraitRef::erase_self_ty(self, trait_ref), - ); + let trait_ref = ty::TraitRef::identity(tcx, trait_def_id); - let mut associated_types = traits::supertraits(self, ty::Binder::dummy(trait_ref)) - .flat_map(|super_trait_ref| { - self.associated_items(super_trait_ref.def_id()) - .map(move |item| (super_trait_ref, item)) - }) - .filter(|(_, item)| item.kind == ty::AssocKind::Type) - .collect::>(); - - // existential predicates need to be in a specific order - associated_types.sort_by_cached_key(|(_, item)| self.def_path_hash(item.def_id)); - - let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| { - // We *can* get bound lifetimes here in cases like - // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`. - // - // binder moved to (*)... - let super_trait_ref = super_trait_ref.skip_binder(); - ty::ExistentialPredicate::Projection(ty::ExistentialProjection { - ty: self.mk_projection(item.def_id, super_trait_ref.substs), - item_def_id: item.def_id, - substs: super_trait_ref.substs, - }) - }); - - let existential_predicates = self - .mk_existential_predicates(iter::once(trait_predicate).chain(projection_predicates)); - - let object_ty = self.mk_dynamic( - // (*) ... binder re-introduced here - ty::Binder::bind(existential_predicates), - lifetime, - ); + let trait_predicate = + ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); - debug!("object_ty_for_trait: object_ty=`{}`", object_ty); + let mut associated_types = traits::supertraits(tcx, ty::Binder::dummy(trait_ref)) + .flat_map(|super_trait_ref| { + tcx.associated_items(super_trait_ref.def_id()).map(move |item| (super_trait_ref, item)) + }) + .filter(|(_, item)| item.kind == ty::AssocKind::Type) + .collect::>(); - object_ty - } + // existential predicates need to be in a specific order + associated_types.sort_by_cached_key(|(_, item)| tcx.def_path_hash(item.def_id)); - /// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a - /// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type - /// in the following way: - /// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc`, - /// - require the following bound: - /// - /// ``` - /// Receiver[Self => T]: DispatchFromDyn dyn Trait]> - /// ``` - /// - /// where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`" - /// (substitution notation). - /// - /// Some examples of receiver types and their required obligation: - /// - `&'a mut self` requires `&'a mut Self: DispatchFromDyn<&'a mut dyn Trait>`, - /// - `self: Rc` requires `Rc: DispatchFromDyn>`, - /// - `self: Pin>` requires `Pin>: DispatchFromDyn>>`. - /// - /// The only case where the receiver is not dispatchable, but is still a valid receiver - /// type (just not object-safe), is when there is more than one level of pointer indirection. - /// E.g., `self: &&Self`, `self: &Rc`, `self: Box>`. In these cases, there - /// is no way, or at least no inexpensive way, to coerce the receiver from the version where - /// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type - /// contained by the trait object, because the object that needs to be coerced is behind - /// a pointer. - /// - /// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result - /// in a new check that `Trait` is object safe, creating a cycle (until object_safe_for_dispatch - /// is stabilized, see tracking issue https://github.com/rust-lang/rust/issues/43561). - /// Instead, we fudge a little by introducing a new type parameter `U` such that - /// `Self: Unsize` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`. - /// Written as a chalk-style query: - /// - /// forall (U: Trait + ?Sized) { - /// if (Self: Unsize) { - /// Receiver: DispatchFromDyn U]> - /// } - /// } - /// - /// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>` - /// for `self: Rc`, this means `Rc: DispatchFromDyn>` - /// for `self: Pin>`, this means `Pin>: DispatchFromDyn>>` - // - // FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this - // fallback query: `Receiver: Unsize U]>` to support receivers like - // `self: Wrapper`. - #[allow(dead_code)] - fn receiver_is_dispatchable(self, method: &ty::AssocItem, receiver_ty: Ty<'tcx>) -> bool { - debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty); - - let traits = - (self.lang_items().unsize_trait(), self.lang_items().dispatch_from_dyn_trait()); - let (unsize_did, dispatch_from_dyn_did) = if let (Some(u), Some(cu)) = traits { - (u, cu) - } else { - debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits"); - return false; - }; + let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| { + // We *can* get bound lifetimes here in cases like + // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`. + // + // binder moved to (*)... + let super_trait_ref = super_trait_ref.skip_binder(); + ty::ExistentialPredicate::Projection(ty::ExistentialProjection { + ty: tcx.mk_projection(item.def_id, super_trait_ref.substs), + item_def_id: item.def_id, + substs: super_trait_ref.substs, + }) + }); - // the type `U` in the query - // use a bogus type parameter to mimick a forall(U) query using u32::MAX for now. - // FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can - // replace this with `dyn Trait` - let unsized_self_ty: Ty<'tcx> = - self.mk_ty_param(::std::u32::MAX, Symbol::intern("RustaceansAreAwesome")); - - // `Receiver[Self => U]` - let unsized_receiver_ty = - self.receiver_for_self_ty(receiver_ty, unsized_self_ty, method.def_id); - - // create a modified param env, with `Self: Unsize` and `U: Trait` added to caller bounds - // `U: ?Sized` is already implied here - let param_env = { - let mut param_env = self.param_env(method.def_id); - - // Self: Unsize - let unsize_predicate = ty::TraitRef { - def_id: unsize_did, - substs: self.mk_substs_trait(self.types.self_param, &[unsized_self_ty.into()]), - } - .to_predicate(); - - // U: Trait - let trait_predicate = { - let substs = - InternalSubsts::for_item(self, method.container.assert_trait(), |param, _| { - if param.index == 0 { - unsized_self_ty.into() - } else { - self.mk_param_from_def(param) - } - }); - - ty::TraitRef { def_id: unsize_did, substs }.to_predicate() - }; + let existential_predicates = + tcx.mk_existential_predicates(iter::once(trait_predicate).chain(projection_predicates)); - let caller_bounds: Vec> = param_env - .caller_bounds - .iter() - .cloned() - .chain(iter::once(unsize_predicate)) - .chain(iter::once(trait_predicate)) - .collect(); + let object_ty = tcx.mk_dynamic( + // (*) ... binder re-introduced here + ty::Binder::bind(existential_predicates), + lifetime, + ); - param_env.caller_bounds = self.intern_predicates(&caller_bounds); + debug!("object_ty_for_trait: object_ty=`{}`", object_ty); - param_env - }; + object_ty +} - // Receiver: DispatchFromDyn U]> - let obligation = { - let predicate = ty::TraitRef { - def_id: dispatch_from_dyn_did, - substs: self.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]), - } - .to_predicate(); +/// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a +/// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type +/// in the following way: +/// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc`, +/// - require the following bound: +/// +/// ``` +/// Receiver[Self => T]: DispatchFromDyn dyn Trait]> +/// ``` +/// +/// where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`" +/// (substitution notation). +/// +/// Some examples of receiver types and their required obligation: +/// - `&'a mut self` requires `&'a mut Self: DispatchFromDyn<&'a mut dyn Trait>`, +/// - `self: Rc` requires `Rc: DispatchFromDyn>`, +/// - `self: Pin>` requires `Pin>: DispatchFromDyn>>`. +/// +/// The only case where the receiver is not dispatchable, but is still a valid receiver +/// type (just not object-safe), is when there is more than one level of pointer indirection. +/// E.g., `self: &&Self`, `self: &Rc`, `self: Box>`. In these cases, there +/// is no way, or at least no inexpensive way, to coerce the receiver from the version where +/// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type +/// contained by the trait object, because the object that needs to be coerced is behind +/// a pointer. +/// +/// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result +/// in a new check that `Trait` is object safe, creating a cycle (until object_safe_for_dispatch +/// is stabilized, see tracking issue https://github.com/rust-lang/rust/issues/43561). +/// Instead, we fudge a little by introducing a new type parameter `U` such that +/// `Self: Unsize` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`. +/// Written as a chalk-style query: +/// +/// forall (U: Trait + ?Sized) { +/// if (Self: Unsize) { +/// Receiver: DispatchFromDyn U]> +/// } +/// } +/// +/// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>` +/// for `self: Rc`, this means `Rc: DispatchFromDyn>` +/// for `self: Pin>`, this means `Pin>: DispatchFromDyn>>` +// +// FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this +// fallback query: `Receiver: Unsize U]>` to support receivers like +// `self: Wrapper`. +#[allow(dead_code)] +fn receiver_is_dispatchable<'tcx>( + tcx: TyCtxt<'tcx>, + method: &ty::AssocItem, + receiver_ty: Ty<'tcx>, +) -> bool { + debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty); + + let traits = (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait()); + let (unsize_did, dispatch_from_dyn_did) = if let (Some(u), Some(cu)) = traits { + (u, cu) + } else { + debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits"); + return false; + }; + + // the type `U` in the query + // use a bogus type parameter to mimick a forall(U) query using u32::MAX for now. + // FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can + // replace this with `dyn Trait` + let unsized_self_ty: Ty<'tcx> = + tcx.mk_ty_param(::std::u32::MAX, Symbol::intern("RustaceansAreAwesome")); + + // `Receiver[Self => U]` + let unsized_receiver_ty = + receiver_for_self_ty(tcx, receiver_ty, unsized_self_ty, method.def_id); + + // create a modified param env, with `Self: Unsize` and `U: Trait` added to caller bounds + // `U: ?Sized` is already implied here + let param_env = { + let mut param_env = tcx.param_env(method.def_id); + + // Self: Unsize + let unsize_predicate = ty::TraitRef { + def_id: unsize_did, + substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]), + } + .to_predicate(); + + // U: Trait + let trait_predicate = { + let substs = + InternalSubsts::for_item(tcx, method.container.assert_trait(), |param, _| { + if param.index == 0 { + unsized_self_ty.into() + } else { + tcx.mk_param_from_def(param) + } + }); - Obligation::new(ObligationCause::dummy(), param_env, predicate) + ty::TraitRef { def_id: unsize_did, substs }.to_predicate() }; - self.infer_ctxt().enter(|ref infcx| { - // the receiver is dispatchable iff the obligation holds - infcx.predicate_must_hold_modulo_regions(&obligation) - }) - } + let caller_bounds: Vec> = param_env + .caller_bounds + .iter() + .cloned() + .chain(iter::once(unsize_predicate)) + .chain(iter::once(trait_predicate)) + .collect(); - fn contains_illegal_self_type_reference(self, trait_def_id: DefId, ty: Ty<'tcx>) -> bool { - // This is somewhat subtle. In general, we want to forbid - // references to `Self` in the argument and return types, - // since the value of `Self` is erased. However, there is one - // exception: it is ok to reference `Self` in order to access - // an associated type of the current trait, since we retain - // the value of those associated types in the object type - // itself. - // - // ```rust - // trait SuperTrait { - // type X; - // } - // - // trait Trait : SuperTrait { - // type Y; - // fn foo(&self, x: Self) // bad - // fn foo(&self) -> Self // bad - // fn foo(&self) -> Option // bad - // fn foo(&self) -> Self::Y // OK, desugars to next example - // fn foo(&self) -> ::Y // OK - // fn foo(&self) -> Self::X // OK, desugars to next example - // fn foo(&self) -> ::X // OK - // } - // ``` - // - // However, it is not as simple as allowing `Self` in a projected - // type, because there are illegal ways to use `Self` as well: - // - // ```rust - // trait Trait : SuperTrait { - // ... - // fn foo(&self) -> ::X; - // } - // ``` - // - // Here we will not have the type of `X` recorded in the - // object type, and we cannot resolve `Self as SomeOtherTrait` - // without knowing what `Self` is. - - let mut supertraits: Option>> = None; - let mut error = false; - let self_ty = self.types.self_param; - ty.maybe_walk(|ty| { - match ty.kind { - ty::Param(_) => { - if ty == self_ty { - error = true; - } + param_env.caller_bounds = tcx.intern_predicates(&caller_bounds); + + param_env + }; + + // Receiver: DispatchFromDyn U]> + let obligation = { + let predicate = ty::TraitRef { + def_id: dispatch_from_dyn_did, + substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]), + } + .to_predicate(); + + Obligation::new(ObligationCause::dummy(), param_env, predicate) + }; - false // no contained types to walk + tcx.infer_ctxt().enter(|ref infcx| { + // the receiver is dispatchable iff the obligation holds + infcx.predicate_must_hold_modulo_regions(&obligation) + }) +} + +fn contains_illegal_self_type_reference<'tcx>( + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + ty: Ty<'tcx>, +) -> bool { + // This is somewhat subtle. In general, we want to forbid + // references to `Self` in the argument and return types, + // since the value of `Self` is erased. However, there is one + // exception: it is ok to reference `Self` in order to access + // an associated type of the current trait, since we retain + // the value of those associated types in the object type + // itself. + // + // ```rust + // trait SuperTrait { + // type X; + // } + // + // trait Trait : SuperTrait { + // type Y; + // fn foo(&self, x: Self) // bad + // fn foo(&self) -> Self // bad + // fn foo(&self) -> Option // bad + // fn foo(&self) -> Self::Y // OK, desugars to next example + // fn foo(&self) -> ::Y // OK + // fn foo(&self) -> Self::X // OK, desugars to next example + // fn foo(&self) -> ::X // OK + // } + // ``` + // + // However, it is not as simple as allowing `Self` in a projected + // type, because there are illegal ways to use `Self` as well: + // + // ```rust + // trait Trait : SuperTrait { + // ... + // fn foo(&self) -> ::X; + // } + // ``` + // + // Here we will not have the type of `X` recorded in the + // object type, and we cannot resolve `Self as SomeOtherTrait` + // without knowing what `Self` is. + + let mut supertraits: Option>> = None; + let mut error = false; + let self_ty = tcx.types.self_param; + ty.maybe_walk(|ty| { + match ty.kind { + ty::Param(_) => { + if ty == self_ty { + error = true; } - ty::Projection(ref data) => { - // This is a projected type `::X`. + false // no contained types to walk + } - // Compute supertraits of current trait lazily. - if supertraits.is_none() { - let trait_ref = - ty::Binder::bind(ty::TraitRef::identity(self, trait_def_id)); - supertraits = Some(traits::supertraits(self, trait_ref).collect()); - } + ty::Projection(ref data) => { + // This is a projected type `::X`. - // Determine whether the trait reference `Foo as - // SomeTrait` is in fact a supertrait of the - // current trait. In that case, this type is - // legal, because the type `X` will be specified - // in the object type. Note that we can just use - // direct equality here because all of these types - // are part of the formal parameter listing, and - // hence there should be no inference variables. - let projection_trait_ref = ty::Binder::bind(data.trait_ref(self)); - let is_supertrait_of_current_trait = - supertraits.as_ref().unwrap().contains(&projection_trait_ref); - - if is_supertrait_of_current_trait { - false // do not walk contained types, do not report error, do collect $200 - } else { - true // DO walk contained types, POSSIBLY reporting an error - } + // Compute supertraits of current trait lazily. + if supertraits.is_none() { + let trait_ref = ty::Binder::bind(ty::TraitRef::identity(tcx, trait_def_id)); + supertraits = Some(traits::supertraits(tcx, trait_ref).collect()); } - _ => true, // walk contained types, if any + // Determine whether the trait reference `Foo as + // SomeTrait` is in fact a supertrait of the + // current trait. In that case, this type is + // legal, because the type `X` will be specified + // in the object type. Note that we can just use + // direct equality here because all of these types + // are part of the formal parameter listing, and + // hence there should be no inference variables. + let projection_trait_ref = ty::Binder::bind(data.trait_ref(tcx)); + let is_supertrait_of_current_trait = + supertraits.as_ref().unwrap().contains(&projection_trait_ref); + + if is_supertrait_of_current_trait { + false // do not walk contained types, do not report error, do collect $200 + } else { + true // DO walk contained types, POSSIBLY reporting an error + } } - }); - error - } + _ => true, // walk contained types, if any + } + }); + + error } pub(super) fn is_object_safe_provider(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { From 0d9f4fb270ce09c12d04c5a913c9e89c59c713fd Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jan 2020 15:52:31 +0100 Subject: [PATCH 04/18] Remove trivial function. --- src/librustc/ty/inhabitedness/mod.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 73ca0075994a5..144e3bc9c8bc6 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -96,15 +96,11 @@ impl<'tcx> TyCtxt<'tcx> { // ``` // forest.is_empty() // ``` - self.ty_inhabitedness_forest(ty).contains(self, module) + ty.uninhabited_from(self).contains(self, module) } pub fn is_ty_uninhabited_from_any_module(self, ty: Ty<'tcx>) -> bool { - !self.ty_inhabitedness_forest(ty).is_empty() - } - - fn ty_inhabitedness_forest(self, ty: Ty<'tcx>) -> DefIdForest { - ty.uninhabited_from(self) + !ty.uninhabited_from(self).is_empty() } } From 640cae257b5c3cbc4b4588e1112b604da1f4c341 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jan 2020 15:57:38 +0100 Subject: [PATCH 05/18] Remove private methods from TyCtxt impl block: rustc::ty::outlives. --- src/librustc/ty/outlives.rs | 50 +++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index 383ccbd337a7d..b397a2c80d59b 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -48,32 +48,29 @@ pub enum Component<'tcx> { impl<'tcx> TyCtxt<'tcx> { /// Push onto `out` all the things that must outlive `'a` for the condition /// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**. - pub fn push_outlives_components( - &self, - ty0: Ty<'tcx>, - out: &mut SmallVec<[Component<'tcx>; 4]>, - ) { - self.compute_components(ty0, out); + pub fn push_outlives_components(self, ty0: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) { + compute_components(self, ty0, out); debug!("components({:?}) = {:?}", ty0, out); } +} - fn compute_components(&self, ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) { - // Descend through the types, looking for the various "base" - // components and collecting them into `out`. This is not written - // with `collect()` because of the need to sometimes skip subtrees - // in the `subtys` iterator (e.g., when encountering a - // projection). - match ty.kind { +fn compute_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) { + // Descend through the types, looking for the various "base" + // components and collecting them into `out`. This is not written + // with `collect()` because of the need to sometimes skip subtrees + // in the `subtys` iterator (e.g., when encountering a + // projection). + match ty.kind { ty::Closure(def_id, ref substs) => { - for upvar_ty in substs.as_closure().upvar_tys(def_id, *self) { - self.compute_components(upvar_ty, out); + for upvar_ty in substs.as_closure().upvar_tys(def_id, tcx) { + compute_components(tcx, upvar_ty, out); } } ty::Generator(def_id, ref substs, _) => { // Same as the closure case - for upvar_ty in substs.as_generator().upvar_tys(def_id, *self) { - self.compute_components(upvar_ty, out); + for upvar_ty in substs.as_generator().upvar_tys(def_id, tcx) { + compute_components(tcx, upvar_ty, out); } // We ignore regions in the generator interior as we don't @@ -110,7 +107,7 @@ impl<'tcx> TyCtxt<'tcx> { // fallback case: hard code // OutlivesProjectionComponents. Continue walking // through and constrain Pi. - let subcomponents = self.capture_components(ty); + let subcomponents = capture_components(tcx, ty); out.push(Component::EscapingProjection(subcomponents)); } } @@ -159,20 +156,19 @@ impl<'tcx> TyCtxt<'tcx> { push_region_constraints(ty, out); for subty in ty.walk_shallow() { - self.compute_components(subty, out); + compute_components(tcx, subty, out); } } } - } +} - fn capture_components(&self, ty: Ty<'tcx>) -> Vec> { - let mut temp = smallvec![]; - push_region_constraints(ty, &mut temp); - for subty in ty.walk_shallow() { - self.compute_components(subty, &mut temp); - } - temp.into_iter().collect() +fn capture_components(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Vec> { + let mut temp = smallvec![]; + push_region_constraints(ty, &mut temp); + for subty in ty.walk_shallow() { + compute_components(tcx, subty, &mut temp); } + temp.into_iter().collect() } fn push_region_constraints<'tcx>(ty: Ty<'tcx>, out: &mut SmallVec<[Component<'tcx>; 4]>) { From 7118e33bfd3313c850b0656fb9d4a655fb450410 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jan 2020 15:59:02 +0100 Subject: [PATCH 06/18] Remove private methods from TyCtxt impl block: rustc::ty::print::pretty. --- src/librustc/ty/print/pretty.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index b3fb455feb5da..16d8934359687 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -1036,26 +1036,26 @@ impl FmtPrinter<'a, 'tcx, F> { } } -impl TyCtxt<'t> { - // HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always - // (but also some things just print a `DefId` generally so maybe we need this?) - fn guess_def_namespace(self, def_id: DefId) -> Namespace { - match self.def_key(def_id).disambiguated_data.data { - DefPathData::TypeNs(..) | DefPathData::CrateRoot | DefPathData::ImplTrait => { - Namespace::TypeNS - } +// HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always +// (but also some things just print a `DefId` generally so maybe we need this?) +fn guess_def_namespace(tcx: TyCtxt<'_>, def_id: DefId) -> Namespace { + match tcx.def_key(def_id).disambiguated_data.data { + DefPathData::TypeNs(..) | DefPathData::CrateRoot | DefPathData::ImplTrait => { + Namespace::TypeNS + } - DefPathData::ValueNs(..) - | DefPathData::AnonConst - | DefPathData::ClosureExpr - | DefPathData::Ctor => Namespace::ValueNS, + DefPathData::ValueNs(..) + | DefPathData::AnonConst + | DefPathData::ClosureExpr + | DefPathData::Ctor => Namespace::ValueNS, - DefPathData::MacroNs(..) => Namespace::MacroNS, + DefPathData::MacroNs(..) => Namespace::MacroNS, - _ => Namespace::TypeNS, - } + _ => Namespace::TypeNS, } +} +impl TyCtxt<'t> { /// Returns a string identifying this `DefId`. This string is /// suitable for user output. pub fn def_path_str(self, def_id: DefId) -> String { @@ -1063,7 +1063,7 @@ impl TyCtxt<'t> { } pub fn def_path_str_with_substs(self, def_id: DefId, substs: &'t [GenericArg<'t>]) -> String { - let ns = self.guess_def_namespace(def_id); + let ns = guess_def_namespace(self, def_id); debug!("def_path_str: def_id={:?}, ns={:?}", def_id, ns); let mut s = String::new(); let _ = FmtPrinter::new(self, &mut s, ns).print_def_path(def_id, substs); From d53bf7a67657fc585e13d14cf5023b5ebdf81021 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jan 2020 16:11:18 +0100 Subject: [PATCH 07/18] Make rustc::infer::error_reporting::{note_and_explain_free_region, note_and_explain_region} free functions. --- src/librustc/infer/error_reporting/mod.rs | 177 +++++++++++---------- src/librustc/infer/error_reporting/note.rs | 105 ++++++++---- src/librustc/infer/opaque_types/mod.rs | 7 +- 3 files changed, 164 insertions(+), 125 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index e653f645881f8..5c2bafd5ae8d7 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -79,98 +79,95 @@ pub use need_type_info::TypeAnnotationNeeded; pub mod nice_region_error; -impl<'tcx> TyCtxt<'tcx> { - pub fn note_and_explain_region( - self, - region_scope_tree: ®ion::ScopeTree, - err: &mut DiagnosticBuilder<'_>, - prefix: &str, - region: ty::Region<'tcx>, - suffix: &str, - ) { - let (description, span) = match *region { - ty::ReScope(scope) => { - let new_string; - let unknown_scope = || { - format!("{}unknown scope: {:?}{}. Please report a bug.", prefix, scope, suffix) - }; - let span = scope.span(self, region_scope_tree); - let tag = match self.hir().find(scope.hir_id(region_scope_tree)) { - Some(Node::Block(_)) => "block", - Some(Node::Expr(expr)) => match expr.kind { - hir::ExprKind::Call(..) => "call", - hir::ExprKind::MethodCall(..) => "method call", - hir::ExprKind::Match(.., hir::MatchSource::IfLetDesugar { .. }) => "if let", - hir::ExprKind::Match(.., hir::MatchSource::WhileLetDesugar) => "while let", - hir::ExprKind::Match(.., hir::MatchSource::ForLoopDesugar) => "for", - hir::ExprKind::Match(..) => "match", - _ => "expression", - }, - Some(Node::Stmt(_)) => "statement", - Some(Node::Item(it)) => item_scope_tag(&it), - Some(Node::TraitItem(it)) => trait_item_scope_tag(&it), - Some(Node::ImplItem(it)) => impl_item_scope_tag(&it), - Some(_) | None => { - err.span_note(span, &unknown_scope()); - return; - } - }; - let scope_decorated_tag = match scope.data { - region::ScopeData::Node => tag, - region::ScopeData::CallSite => "scope of call-site for function", - region::ScopeData::Arguments => "scope of function body", - region::ScopeData::Destruction => { - new_string = format!("destruction scope surrounding {}", tag); - &new_string[..] - } - region::ScopeData::Remainder(first_statement_index) => { - new_string = format!( - "block suffix following statement {}", - first_statement_index.index() - ); - &new_string[..] - } - }; - explain_span(self, scope_decorated_tag, span) - } +pub(super) fn note_and_explain_region( + tcx: TyCtxt<'tcx>, + region_scope_tree: ®ion::ScopeTree, + err: &mut DiagnosticBuilder<'_>, + prefix: &str, + region: ty::Region<'tcx>, + suffix: &str, +) { + let (description, span) = match *region { + ty::ReScope(scope) => { + let new_string; + let unknown_scope = + || format!("{}unknown scope: {:?}{}. Please report a bug.", prefix, scope, suffix); + let span = scope.span(tcx, region_scope_tree); + let tag = match tcx.hir().find(scope.hir_id(region_scope_tree)) { + Some(Node::Block(_)) => "block", + Some(Node::Expr(expr)) => match expr.kind { + hir::ExprKind::Call(..) => "call", + hir::ExprKind::MethodCall(..) => "method call", + hir::ExprKind::Match(.., hir::MatchSource::IfLetDesugar { .. }) => "if let", + hir::ExprKind::Match(.., hir::MatchSource::WhileLetDesugar) => "while let", + hir::ExprKind::Match(.., hir::MatchSource::ForLoopDesugar) => "for", + hir::ExprKind::Match(..) => "match", + _ => "expression", + }, + Some(Node::Stmt(_)) => "statement", + Some(Node::Item(it)) => item_scope_tag(&it), + Some(Node::TraitItem(it)) => trait_item_scope_tag(&it), + Some(Node::ImplItem(it)) => impl_item_scope_tag(&it), + Some(_) | None => { + err.span_note(span, &unknown_scope()); + return; + } + }; + let scope_decorated_tag = match scope.data { + region::ScopeData::Node => tag, + region::ScopeData::CallSite => "scope of call-site for function", + region::ScopeData::Arguments => "scope of function body", + region::ScopeData::Destruction => { + new_string = format!("destruction scope surrounding {}", tag); + &new_string[..] + } + region::ScopeData::Remainder(first_statement_index) => { + new_string = format!( + "block suffix following statement {}", + first_statement_index.index() + ); + &new_string[..] + } + }; + explain_span(tcx, scope_decorated_tag, span) + } - ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => { - msg_span_from_free_region(self, region) - } + ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => { + msg_span_from_free_region(tcx, region) + } - ty::ReEmpty => ("the empty lifetime".to_owned(), None), + ty::ReEmpty => ("the empty lifetime".to_owned(), None), - ty::RePlaceholder(_) => (format!("any other region"), None), + ty::RePlaceholder(_) => (format!("any other region"), None), - // FIXME(#13998) RePlaceholder should probably print like - // ReFree rather than dumping Debug output on the user. - // - // We shouldn't really be having unification failures with ReVar - // and ReLateBound though. - ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => { - (format!("lifetime {:?}", region), None) - } + // FIXME(#13998) RePlaceholder should probably print like + // ReFree rather than dumping Debug output on the user. + // + // We shouldn't really be having unification failures with ReVar + // and ReLateBound though. + ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => { + (format!("lifetime {:?}", region), None) + } - // We shouldn't encounter an error message with ReClosureBound. - ty::ReClosureBound(..) => { - bug!("encountered unexpected ReClosureBound: {:?}", region,); - } - }; + // We shouldn't encounter an error message with ReClosureBound. + ty::ReClosureBound(..) => { + bug!("encountered unexpected ReClosureBound: {:?}", region,); + } + }; - emit_msg_span(err, prefix, description, span, suffix); - } + emit_msg_span(err, prefix, description, span, suffix); +} - pub fn note_and_explain_free_region( - self, - err: &mut DiagnosticBuilder<'_>, - prefix: &str, - region: ty::Region<'tcx>, - suffix: &str, - ) { - let (description, span) = msg_span_from_free_region(self, region); +pub(super) fn note_and_explain_free_region( + tcx: TyCtxt<'tcx>, + err: &mut DiagnosticBuilder<'_>, + prefix: &str, + region: ty::Region<'tcx>, + suffix: &str, +) { + let (description, span) = msg_span_from_free_region(tcx, region); - emit_msg_span(err, prefix, description, span, suffix); - } + emit_msg_span(err, prefix, description, span, suffix); } fn msg_span_from_free_region( @@ -1719,7 +1716,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "consider adding an explicit lifetime bound for `{}`", bound_kind )); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, &format!("{} must be valid for ", labeled_user_string), @@ -1747,7 +1745,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ) { let mut err = self.report_inference_failure(var_origin); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "first, the lifetime cannot outlive ", @@ -1771,7 +1770,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { (self.values_str(&sup_trace.values), self.values_str(&sub_trace.values)) { if sub_expected == sup_expected && sub_found == sup_found { - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "...but the lifetime must also be valid for ", @@ -1794,7 +1794,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.note_region_origin(&mut err, &sup_origin); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "but, the lifetime must be valid for ", diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs index 979bcca619c2f..7919274c37322 100644 --- a/src/librustc/infer/error_reporting/note.rs +++ b/src/librustc/infer/error_reporting/note.rs @@ -1,3 +1,4 @@ +use crate::infer::error_reporting::note_and_explain_region; use crate::infer::{self, InferCtxt, SubregionOrigin}; use crate::middle::region; use crate::ty::error::TypeError; @@ -167,8 +168,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { infer::Subtype(box trace) => { let terr = TypeError::RegionsDoesNotOutlive(sup, sub); let mut err = self.report_and_explain_type_error(trace, &terr); - self.tcx.note_and_explain_region(region_scope_tree, &mut err, "", sup, "..."); - self.tcx.note_and_explain_region( + note_and_explain_region(self.tcx, region_scope_tree, &mut err, "", sup, "..."); + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "...does not necessarily outlive ", @@ -185,14 +187,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "lifetime of reference outlives lifetime of \ borrowed content..." ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "...the reference is valid for ", sub, "...", ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "...but the borrowed content is only valid for ", @@ -211,14 +215,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { of captured variable `{}`...", var_name ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "...the borrowed pointer is valid for ", sub, "...", ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, &format!("...but `{}` is only valid for ", var_name), @@ -230,14 +236,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { infer::InfStackClosure(span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0314, "closure outlives stack frame"); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "...the closure must be valid for ", sub, "...", ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "...but the closure's stack frame is only valid \ @@ -254,7 +262,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { E0315, "cannot invoke closure outside of its lifetime" ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "the closure is only valid for ", @@ -270,7 +279,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { E0473, "dereference of reference outside its lifetime" ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "the reference is only valid for ", @@ -288,14 +298,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { enclosing closure", self.tcx.hir().name(id) ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "captured variable is valid for ", sup, "", ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "closure is valid for ", @@ -311,7 +323,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { E0475, "index of slice outside its lifetime" ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "the slice is only valid for ", @@ -328,14 +341,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "lifetime of the source pointer does not outlive \ lifetime bound of the object type" ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "object type is valid for ", sub, "", ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "source pointer is only valid for ", @@ -354,14 +369,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.ty_to_string(ty) ); match *sub { - ty::ReStatic => self.tcx.note_and_explain_region( + ty::ReStatic => note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "type must satisfy ", sub, "", ), - _ => self.tcx.note_and_explain_region( + _ => note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "type must outlive ", @@ -374,14 +391,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { infer::RelateRegionParamBound(span) => { let mut err = struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied"); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "lifetime parameter instantiated with ", sup, "", ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "but lifetime parameter must outlive ", @@ -399,7 +418,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { parameter) is not valid at this point", self.ty_to_string(ty) ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "type must outlive ", @@ -416,7 +436,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "lifetime of method receiver does not outlive the \ method call" ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "the receiver is only valid for ", @@ -433,7 +454,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "lifetime of function argument does not outlive \ the function call" ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "the function argument is only valid for ", @@ -450,7 +472,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "lifetime of return value does not outlive the \ function call" ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "the return value is only valid for ", @@ -467,7 +490,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "lifetime of operand does not outlive the \ operation" ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "the operand is only valid for ", @@ -483,7 +507,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { E0484, "reference is not valid at the time of borrow" ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "the borrow is only valid for ", @@ -500,7 +525,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "automatically reference is not valid at the time \ of borrow" ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "the automatic borrow is only valid for ", @@ -518,7 +544,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { not valid during the expression: `{}`", self.ty_to_string(t) ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "type is only valid for ", @@ -536,14 +563,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { called while references are dead" ); // FIXME (22171): terms "super/subregion" are suboptimal - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "superregion: ", sup, "", ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "subregion: ", @@ -560,7 +589,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "lifetime of variable does not enclose its \ declaration" ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "the variable is only valid for ", @@ -576,7 +606,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { E0489, "type/lifetime parameter not in scope here" ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "the parameter is only valid for ", @@ -593,14 +624,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "a value of type `{}` is borrowed for too long", self.ty_to_string(ty) ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "the type is valid for ", sub, "", ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "but the borrow lasts for ", @@ -618,14 +651,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { than the data it references", self.ty_to_string(ty) ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "the pointer is valid for ", sub, "", ); - self.tcx.note_and_explain_region( + note_and_explain_region( + self.tcx, region_scope_tree, &mut err, "but the referenced data is only valid for ", diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index e9b1ebbd3f643..834b8e8e72e02 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -1,3 +1,4 @@ +use crate::infer::error_reporting::{note_and_explain_free_region, note_and_explain_region}; use crate::infer::outlives::free_region_map::FreeRegionRelations; use crate::infer::{self, InferCtxt, InferOk, TypeVariableOrigin, TypeVariableOriginKind}; use crate::middle::region; @@ -624,7 +625,8 @@ pub fn unexpected_hidden_region_diagnostic( // // (*) if not, the `tainted_by_errors` flag would be set to // true in any case, so we wouldn't be here at all. - tcx.note_and_explain_free_region( + note_and_explain_free_region( + tcx, &mut err, &format!("hidden type `{}` captures ", hidden_ty), hidden_region, @@ -649,7 +651,8 @@ pub fn unexpected_hidden_region_diagnostic( // If the `region_scope_tree` is available, this is being // invoked from the "region inferencer error". We can at // least report a really cryptic error for now. - tcx.note_and_explain_region( + note_and_explain_region( + tcx, region_scope_tree, &mut err, &format!("hidden type `{}` captures ", hidden_ty), From 0b1521e6d3ed756f3b2024291edbe0c9e74cb08c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jan 2020 17:51:09 +0100 Subject: [PATCH 08/18] Make rustc::traits::error_reporting::{recursive_type_with_infinite_size_error, report_object_safety_error} free functions. --- src/librustc/infer/error_reporting/mod.rs | 3 +- src/librustc/traits/error_reporting.rs | 108 +++++++++++----------- src/librustc_typeck/astconv.rs | 4 +- src/librustc_typeck/check/cast.rs | 3 +- src/librustc_typeck/check/mod.rs | 3 +- 5 files changed, 62 insertions(+), 59 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 5c2bafd5ae8d7..1d1135ef2ed25 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -53,6 +53,7 @@ use crate::hir::map; use crate::infer::opaque_types; use crate::infer::{self, SuppressRegionErrors}; use crate::middle::region; +use crate::traits::error_reporting::report_object_safety_error; use crate::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, }; @@ -1487,7 +1488,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let mut diag = match failure_code { FailureCode::Error0038(did) => { let violations = self.tcx.object_safety_violations(did); - self.tcx.report_object_safety_error(span, did, violations) + report_object_safety_error(self.tcx, span, did, violations) } FailureCode::Error0317(failure_str) => { struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index b5030f3efe9ca..7fa5a495621dd 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -916,7 +916,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty::Predicate::ObjectSafe(trait_def_id) => { let violations = self.tcx.object_safety_violations(trait_def_id); - self.tcx.report_object_safety_error(span, trait_def_id, violations) + report_object_safety_error(self.tcx, span, trait_def_id, violations) } ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { @@ -1080,7 +1080,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { TraitNotObjectSafe(did) => { let violations = self.tcx.object_safety_violations(did); - self.tcx.report_object_safety_error(span, did, violations) + report_object_safety_error(self.tcx, span, did, violations) } // already reported in the query @@ -1945,64 +1945,62 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } -impl<'tcx> TyCtxt<'tcx> { - pub fn recursive_type_with_infinite_size_error( - self, - type_def_id: DefId, - ) -> DiagnosticBuilder<'tcx> { - assert!(type_def_id.is_local()); - let span = self.hir().span_if_local(type_def_id).unwrap(); - let span = self.sess.source_map().def_span(span); - let mut err = struct_span_err!( - self.sess, - span, - E0072, - "recursive type `{}` has infinite size", - self.def_path_str(type_def_id) - ); - err.span_label(span, "recursive type has infinite size"); - err.help(&format!( - "insert indirection (e.g., a `Box`, `Rc`, or `&`) \ +pub fn recursive_type_with_infinite_size_error( + tcx: TyCtxt<'tcx>, + type_def_id: DefId, +) -> DiagnosticBuilder<'tcx> { + assert!(type_def_id.is_local()); + let span = tcx.hir().span_if_local(type_def_id).unwrap(); + let span = tcx.sess.source_map().def_span(span); + let mut err = struct_span_err!( + tcx.sess, + span, + E0072, + "recursive type `{}` has infinite size", + tcx.def_path_str(type_def_id) + ); + err.span_label(span, "recursive type has infinite size"); + err.help(&format!( + "insert indirection (e.g., a `Box`, `Rc`, or `&`) \ at some point to make `{}` representable", - self.def_path_str(type_def_id) - )); - err - } - - pub fn report_object_safety_error( - self, - span: Span, - trait_def_id: DefId, - violations: Vec, - ) -> DiagnosticBuilder<'tcx> { - let trait_str = self.def_path_str(trait_def_id); - let span = self.sess.source_map().def_span(span); - let mut err = struct_span_err!( - self.sess, - span, - E0038, - "the trait `{}` cannot be made into an object", - trait_str - ); - err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str)); - - let mut reported_violations = FxHashSet::default(); - for violation in violations { - if reported_violations.insert(violation.clone()) { - match violation.span() { - Some(span) => err.span_label(span, violation.error_msg()), - None => err.note(&violation.error_msg()), - }; - } - } + tcx.def_path_str(type_def_id) + )); + err +} - if self.sess.trait_methods_not_found.borrow().contains(&span) { - // Avoid emitting error caused by non-existing method (#58734) - err.cancel(); +pub fn report_object_safety_error( + tcx: TyCtxt<'tcx>, + span: Span, + trait_def_id: DefId, + violations: Vec, +) -> DiagnosticBuilder<'tcx> { + let trait_str = tcx.def_path_str(trait_def_id); + let span = tcx.sess.source_map().def_span(span); + let mut err = struct_span_err!( + tcx.sess, + span, + E0038, + "the trait `{}` cannot be made into an object", + trait_str + ); + err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str)); + + let mut reported_violations = FxHashSet::default(); + for violation in violations { + if reported_violations.insert(violation.clone()) { + match violation.span() { + Some(span) => err.span_label(span, violation.error_msg()), + None => err.note(&violation.error_msg()), + }; } + } - err + if tcx.sess.trait_methods_not_found.borrow().contains(&span) { + // Avoid emitting error caused by non-existing method (#58734) + err.cancel(); } + + err } impl<'a, 'tcx> InferCtxt<'a, 'tcx> { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 36d119bf7698f..a7da2df9fb792 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -13,6 +13,7 @@ use errors::{Applicability, DiagnosticId}; use rustc::hir::intravisit::Visitor; use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc::traits; +use rustc::traits::error_reporting::report_object_safety_error; use rustc::ty::subst::{self, InternalSubsts, Subst, SubstsRef}; use rustc::ty::wf::object_region_bounds; use rustc::ty::{self, Const, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable}; @@ -1454,7 +1455,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let object_safety_violations = tcx.astconv_object_safety_violations(item.trait_ref().def_id()); if !object_safety_violations.is_empty() { - tcx.report_object_safety_error( + report_object_safety_error( + tcx, span, item.trait_ref().def_id(), object_safety_violations, diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 332921f45f4d5..1a4aa089549e5 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -37,6 +37,7 @@ use errors::{Applicability, DiagnosticBuilder}; use rustc::middle::lang_items; use rustc::session::Session; use rustc::traits; +use rustc::traits::error_reporting::report_object_safety_error; use rustc::ty::adjustment::AllowTwoPhase; use rustc::ty::cast::{CastKind, CastTy}; use rustc::ty::error::TypeError; @@ -519,7 +520,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { fn report_object_unsafe_cast(&self, fcx: &FnCtxt<'a, 'tcx>, did: DefId) { let violations = fcx.tcx.object_safety_violations(did); - let mut err = fcx.tcx.report_object_safety_error(self.cast_span, did, violations); + let mut err = report_object_safety_error(fcx.tcx, self.cast_span, did, violations); err.note(&format!("required by cast to type '{}'", fcx.ty_to_string(self.cast_ty))); err.emit(); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index eacd94f7da7f7..430513ba803cc 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -100,6 +100,7 @@ use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc::infer::{self, InferCtxt, InferOk, InferResult}; use rustc::middle::region; use rustc::mir::interpret::ConstValue; +use rustc::traits::error_reporting::recursive_type_with_infinite_size_error; use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine}; use rustc::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast, @@ -2222,7 +2223,7 @@ fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: DefId) -> bool { // caught by case 1. match rty.is_representable(tcx, sp) { Representability::SelfRecursive(spans) => { - let mut err = tcx.recursive_type_with_infinite_size_error(item_def_id); + let mut err = recursive_type_with_infinite_size_error(tcx, item_def_id); for span in spans { err.span_label(span, "recursive without indirection"); } From 7770bce1788169e15186412b0eb035adb5c8eb4b Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jan 2020 18:07:29 +0100 Subject: [PATCH 09/18] Make rustc::traits::object_safety::{astconv_object_safety_violations,is_vtable_safe_method,object_safety_violations} free functions. --- src/librustc/infer/error_reporting/mod.rs | 3 +- src/librustc/traits/error_reporting.rs | 5 +- src/librustc/traits/mod.rs | 5 +- src/librustc/traits/object_safety.rs | 84 +++++++++++------------ src/librustc_typeck/astconv.rs | 3 +- src/librustc_typeck/check/cast.rs | 3 +- 6 files changed, 54 insertions(+), 49 deletions(-) diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 1d1135ef2ed25..f262672fdc875 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -54,6 +54,7 @@ use crate::infer::opaque_types; use crate::infer::{self, SuppressRegionErrors}; use crate::middle::region; use crate::traits::error_reporting::report_object_safety_error; +use crate::traits::object_safety_violations; use crate::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, }; @@ -1487,7 +1488,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let failure_code = trace.cause.as_failure_code(terr); let mut diag = match failure_code { FailureCode::Error0038(did) => { - let violations = self.tcx.object_safety_violations(did); + let violations = object_safety_violations(self.tcx, did); report_object_safety_error(self.tcx, span, did, violations) } FailureCode::Error0317(failure_str) => { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 7fa5a495621dd..172330dbc7ee5 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -11,6 +11,7 @@ use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{self, InferCtxt}; use crate::mir::interpret::ErrorHandled; use crate::session::DiagnosticMessageId; +use crate::traits::object_safety_violations; use crate::ty::error::ExpectedFound; use crate::ty::fast_reject; use crate::ty::fold::TypeFolder; @@ -915,7 +916,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } ty::Predicate::ObjectSafe(trait_def_id) => { - let violations = self.tcx.object_safety_violations(trait_def_id); + let violations = object_safety_violations(self.tcx, trait_def_id); report_object_safety_error(self.tcx, span, trait_def_id, violations) } @@ -1079,7 +1080,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } TraitNotObjectSafe(did) => { - let violations = self.tcx.object_safety_violations(did); + let violations = object_safety_violations(self.tcx, did); report_object_safety_error(self.tcx, span, did, violations) } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 3ba673d1a7d49..0c315b3d6efc8 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -47,6 +47,9 @@ pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls} pub use self::coherence::{OrphanCheckErr, OverlapResult}; pub use self::engine::{TraitEngine, TraitEngineExt}; pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation}; +pub use self::object_safety::astconv_object_safety_violations; +pub use self::object_safety::is_vtable_safe_method; +pub use self::object_safety::object_safety_violations; pub use self::object_safety::MethodViolationCode; pub use self::object_safety::ObjectSafetyViolation; pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote}; @@ -1062,7 +1065,7 @@ fn vtable_methods<'tcx>( let def_id = trait_method.def_id; // Some methods cannot be called on an object; skip those. - if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) { + if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) { debug!("vtable_methods: not vtable safe"); return None; } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 3c64a46661d05..bfbcb042e7a73 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -108,54 +108,52 @@ pub enum MethodViolationCode { UndispatchableReceiver, } -impl<'tcx> TyCtxt<'tcx> { - /// Returns the object safety violations that affect - /// astconv -- currently, `Self` in supertraits. This is needed - /// because `object_safety_violations` can't be used during - /// type collection. - pub fn astconv_object_safety_violations( - self, - trait_def_id: DefId, - ) -> Vec { - debug_assert!(self.generics_of(trait_def_id).has_self); - let violations = traits::supertrait_def_ids(self, trait_def_id) - .filter(|&def_id| predicates_reference_self(self, def_id, true)) - .map(|_| ObjectSafetyViolation::SupertraitSelf) - .collect(); +/// Returns the object safety violations that affect +/// astconv -- currently, `Self` in supertraits. This is needed +/// because `object_safety_violations` can't be used during +/// type collection. +pub fn astconv_object_safety_violations( + tcx: TyCtxt<'_>, + trait_def_id: DefId, +) -> Vec { + debug_assert!(tcx.generics_of(trait_def_id).has_self); + let violations = traits::supertrait_def_ids(tcx, trait_def_id) + .filter(|&def_id| predicates_reference_self(tcx, def_id, true)) + .map(|_| ObjectSafetyViolation::SupertraitSelf) + .collect(); - debug!( - "astconv_object_safety_violations(trait_def_id={:?}) = {:?}", - trait_def_id, violations - ); + debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}", trait_def_id, violations); - violations - } + violations +} + +pub fn object_safety_violations( + tcx: TyCtxt<'_>, + trait_def_id: DefId, +) -> Vec { + debug_assert!(tcx.generics_of(trait_def_id).has_self); + debug!("object_safety_violations: {:?}", trait_def_id); - pub fn object_safety_violations(self, trait_def_id: DefId) -> Vec { - debug_assert!(self.generics_of(trait_def_id).has_self); - debug!("object_safety_violations: {:?}", trait_def_id); + traits::supertrait_def_ids(tcx, trait_def_id) + .flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id)) + .collect() +} - traits::supertrait_def_ids(self, trait_def_id) - .flat_map(|def_id| object_safety_violations_for_trait(self, def_id)) - .collect() +/// We say a method is *vtable safe* if it can be invoked on a trait +/// object. Note that object-safe traits can have some +/// non-vtable-safe methods, so long as they require `Self: Sized` or +/// otherwise ensure that they cannot be used when `Self = Trait`. +pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: &ty::AssocItem) -> bool { + debug_assert!(tcx.generics_of(trait_def_id).has_self); + debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method); + // Any method that has a `Self: Sized` bound cannot be called. + if generics_require_sized_self(tcx, method.def_id) { + return false; } - /// We say a method is *vtable safe* if it can be invoked on a trait - /// object. Note that object-safe traits can have some - /// non-vtable-safe methods, so long as they require `Self: Sized` or - /// otherwise ensure that they cannot be used when `Self = Trait`. - pub fn is_vtable_safe_method(self, trait_def_id: DefId, method: &ty::AssocItem) -> bool { - debug_assert!(self.generics_of(trait_def_id).has_self); - debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method); - // Any method that has a `Self: Sized` bound cannot be called. - if generics_require_sized_self(self, method.def_id) { - return false; - } - - match virtual_call_violation_for_method(self, trait_def_id, method) { - None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true, - Some(_) => false, - } + match virtual_call_violation_for_method(tcx, trait_def_id, method) { + None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true, + Some(_) => false, } } @@ -724,5 +722,5 @@ fn contains_illegal_self_type_reference<'tcx>( } pub(super) fn is_object_safe_provider(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { - tcx.object_safety_violations(trait_def_id).is_empty() + object_safety_violations(tcx, trait_def_id).is_empty() } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index a7da2df9fb792..82c97af1be4ed 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -13,6 +13,7 @@ use errors::{Applicability, DiagnosticId}; use rustc::hir::intravisit::Visitor; use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc::traits; +use rustc::traits::astconv_object_safety_violations; use rustc::traits::error_reporting::report_object_safety_error; use rustc::ty::subst::{self, InternalSubsts, Subst, SubstsRef}; use rustc::ty::wf::object_region_bounds; @@ -1453,7 +1454,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // to avoid ICEs. for item in ®ular_traits { let object_safety_violations = - tcx.astconv_object_safety_violations(item.trait_ref().def_id()); + astconv_object_safety_violations(tcx, item.trait_ref().def_id()); if !object_safety_violations.is_empty() { report_object_safety_error( tcx, diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 1a4aa089549e5..0be21ad58be4b 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -38,6 +38,7 @@ use rustc::middle::lang_items; use rustc::session::Session; use rustc::traits; use rustc::traits::error_reporting::report_object_safety_error; +use rustc::traits::object_safety_violations; use rustc::ty::adjustment::AllowTwoPhase; use rustc::ty::cast::{CastKind, CastTy}; use rustc::ty::error::TypeError; @@ -519,7 +520,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } fn report_object_unsafe_cast(&self, fcx: &FnCtxt<'a, 'tcx>, did: DefId) { - let violations = fcx.tcx.object_safety_violations(did); + let violations = object_safety_violations(fcx.tcx, did); let mut err = report_object_safety_error(fcx.tcx, self.cast_span, did, violations); err.note(&format!("required by cast to type '{}'", fcx.ty_to_string(self.cast_ty))); err.emit(); From a80bff87c19cf91deafefc8fdaace71f77727258 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jan 2020 19:43:25 +0100 Subject: [PATCH 10/18] Move normalize_erasing_regions to rustc::ty. --- src/librustc/traits/query/mod.rs | 1 - src/librustc/ty/mod.rs | 1 + src/librustc/{traits/query => ty}/normalize_erasing_regions.rs | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename src/librustc/{traits/query => ty}/normalize_erasing_regions.rs (100%) diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs index fb9f46011b99b..440268aab8fb3 100644 --- a/src/librustc/traits/query/mod.rs +++ b/src/librustc/traits/query/mod.rs @@ -13,7 +13,6 @@ pub mod dropck_outlives; pub mod evaluate_obligation; pub mod method_autoderef; pub mod normalize; -pub mod normalize_erasing_regions; pub mod outlives_bounds; pub mod type_op; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 1698a0685b7aa..6e7a4d6c53e29 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -109,6 +109,7 @@ pub mod flags; pub mod fold; pub mod inhabitedness; pub mod layout; +pub mod normalize_erasing_regions; pub mod outlives; pub mod print; pub mod query; diff --git a/src/librustc/traits/query/normalize_erasing_regions.rs b/src/librustc/ty/normalize_erasing_regions.rs similarity index 100% rename from src/librustc/traits/query/normalize_erasing_regions.rs rename to src/librustc/ty/normalize_erasing_regions.rs From 56a0aec07fa998e43702216a7e18133af481c076 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jan 2020 19:52:56 +0100 Subject: [PATCH 11/18] Move subst_and_normalize_erasing_regionsto rustc::ty. --- src/librustc/traits/codegen/mod.rs | 26 -------------------- src/librustc/ty/normalize_erasing_regions.rs | 24 ++++++++++++++++++ 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/librustc/traits/codegen/mod.rs b/src/librustc/traits/codegen/mod.rs index 8bd3f3141d53d..8a264a79fb6c2 100644 --- a/src/librustc/traits/codegen/mod.rs +++ b/src/librustc/traits/codegen/mod.rs @@ -8,7 +8,6 @@ use crate::traits::{ FulfillmentContext, Obligation, ObligationCause, SelectionContext, TraitEngine, Vtable, }; use crate::ty::fold::TypeFoldable; -use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::{self, TyCtxt}; /// Attempts to resolve an obligation to a vtable. The result is @@ -76,31 +75,6 @@ pub fn codegen_fulfill_obligation<'tcx>( }) } -impl<'tcx> TyCtxt<'tcx> { - /// Monomorphizes a type from the AST by first applying the - /// in-scope substitutions and then normalizing any associated - /// types. - pub fn subst_and_normalize_erasing_regions( - self, - param_substs: SubstsRef<'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: &T, - ) -> T - where - T: TypeFoldable<'tcx>, - { - debug!( - "subst_and_normalize_erasing_regions(\ - param_substs={:?}, \ - value={:?}, \ - param_env={:?})", - param_substs, value, param_env, - ); - let substituted = value.subst(self, param_substs); - self.normalize_erasing_regions(param_env, substituted) - } -} - // # Global Cache impl<'a, 'tcx> InferCtxt<'a, 'tcx> { diff --git a/src/librustc/ty/normalize_erasing_regions.rs b/src/librustc/ty/normalize_erasing_regions.rs index 2fa52e8810bd9..dc64482907f75 100644 --- a/src/librustc/ty/normalize_erasing_regions.rs +++ b/src/librustc/ty/normalize_erasing_regions.rs @@ -8,6 +8,7 @@ //! within. (This underlying query is what is cached.) use crate::ty::fold::{TypeFoldable, TypeFolder}; +use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::{self, Ty, TyCtxt}; impl<'tcx> TyCtxt<'tcx> { @@ -60,6 +61,29 @@ impl<'tcx> TyCtxt<'tcx> { let value = self.erase_late_bound_regions(value); self.normalize_erasing_regions(param_env, value) } + + /// Monomorphizes a type from the AST by first applying the + /// in-scope substitutions and then normalizing any associated + /// types. + pub fn subst_and_normalize_erasing_regions( + self, + param_substs: SubstsRef<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: &T, + ) -> T + where + T: TypeFoldable<'tcx>, + { + debug!( + "subst_and_normalize_erasing_regions(\ + param_substs={:?}, \ + value={:?}, \ + param_env={:?})", + param_substs, value, param_env, + ); + let substituted = value.subst(self, param_substs); + self.normalize_erasing_regions(param_env, substituted) + } } struct NormalizeAfterErasingRegionsFolder<'tcx> { From 787cd5493a1078a12587d1ce83b2ff85ac667990 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jan 2020 20:27:00 +0100 Subject: [PATCH 12/18] Make traits::util::* free functions. --- src/librustc/traits/mod.rs | 4 + src/librustc/traits/project.rs | 74 ++++--- src/librustc/traits/select.rs | 59 ++--- src/librustc/traits/util.rs | 202 +++++++++--------- src/librustc/ty/instance.rs | 2 +- src/librustc_mir/hair/pattern/const_to_pat.rs | 4 +- src/librustc_typeck/check/coercion.rs | 3 +- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/mod.rs | 6 +- src/librustc_typeck/coherence/builtin.rs | 7 +- 10 files changed, 189 insertions(+), 174 deletions(-) diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 0c315b3d6efc8..a2ccfc5de8abc 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -64,6 +64,10 @@ pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; pub use self::specialize::{specialization_graph, translate_substs, OverlapError}; pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs}; pub use self::util::{expand_trait_aliases, TraitAliasExpander}; +pub use self::util::{ + get_vtable_index_of_object_method, impl_is_default, impl_item_is_final, + predicate_for_trait_def, upcast_choices, +}; pub use self::util::{ supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits, }; diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 22bfba37443fd..79e1b6444a9b7 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -1057,7 +1057,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( node_item.item.defaultness.has_value() } else { node_item.item.defaultness.is_default() - || selcx.tcx().impl_is_default(node_item.node.def_id()) + || super::util::impl_is_default(selcx.tcx(), node_item.node.def_id()) }; // Only reveal a specializable default if we're past type-checking @@ -1263,26 +1263,30 @@ fn confirm_generator_candidate<'cx, 'tcx>( let gen_def_id = tcx.lang_items().gen_trait().unwrap(); - let predicate = tcx - .generator_trait_ref_and_outputs(gen_def_id, obligation.predicate.self_ty(), gen_sig) - .map_bound(|(trait_ref, yield_ty, return_ty)| { - let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name; - let ty = if name == sym::Return { - return_ty - } else if name == sym::Yield { - yield_ty - } else { - bug!() - }; + let predicate = super::util::generator_trait_ref_and_outputs( + tcx, + gen_def_id, + obligation.predicate.self_ty(), + gen_sig, + ) + .map_bound(|(trait_ref, yield_ty, return_ty)| { + let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name; + let ty = if name == sym::Return { + return_ty + } else if name == sym::Yield { + yield_ty + } else { + bug!() + }; - ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { - substs: trait_ref.substs, - item_def_id: obligation.predicate.item_def_id, - }, - ty: ty, - } - }); + ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { + substs: trait_ref.substs, + item_def_id: obligation.predicate.item_def_id, + }, + ty: ty, + } + }); confirm_param_env_candidate(selcx, obligation, predicate) .with_addl_obligations(vtable.nested) @@ -1349,21 +1353,21 @@ fn confirm_callable_candidate<'cx, 'tcx>( // the `Output` associated type is declared on `FnOnce` let fn_once_def_id = tcx.lang_items().fn_once_trait().unwrap(); - let predicate = tcx - .closure_trait_ref_and_return_type( - fn_once_def_id, - obligation.predicate.self_ty(), - fn_sig, - flag, - ) - .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy::from_ref_and_name( - tcx, - trait_ref, - Ident::with_dummy_span(FN_OUTPUT_NAME), - ), - ty: ret_type, - }); + let predicate = super::util::closure_trait_ref_and_return_type( + tcx, + fn_once_def_id, + obligation.predicate.self_ty(), + fn_sig, + flag, + ) + .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy::from_ref_and_name( + tcx, + trait_ref, + Ident::with_dummy_span(FN_OUTPUT_NAME), + ), + ty: ret_type, + }); confirm_param_env_candidate(selcx, obligation, predicate) } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 94d5723778a9a..3a9ed633740bf 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -11,6 +11,7 @@ use super::coherence::{self, Conflict}; use super::project; use super::project::{normalize_with_depth, Normalized, ProjectionCacheKey}; use super::util; +use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; use super::DerivedObligationCause; use super::Selection; use super::SelectionResult; @@ -2651,7 +2652,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { recursion_depth, &skol_ty, ); - let skol_obligation = self.tcx().predicate_for_trait_def( + let skol_obligation = predicate_for_trait_def( + self.tcx(), param_env, cause.clone(), trait_def_id, @@ -2988,7 +2990,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // we pass over, we sum up the set of number of vtable // entries, so that we can compute the offset for the selected // trait. - vtable_base = nonmatching.map(|t| tcx.count_own_vtable_entries(t)).sum(); + vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum(); } VtableObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), vtable_base, nested } @@ -3003,15 +3005,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Okay to skip binder; it is reintroduced below. let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); let sig = self_ty.fn_sig(self.tcx()); - let trait_ref = self - .tcx() - .closure_trait_ref_and_return_type( - obligation.predicate.def_id(), - self_ty, - sig, - util::TupleArgumentsFlag::Yes, - ) - .map_bound(|(trait_ref, _)| trait_ref); + let trait_ref = closure_trait_ref_and_return_type( + self.tcx(), + obligation.predicate.def_id(), + self_ty, + sig, + util::TupleArgumentsFlag::Yes, + ) + .map_bound(|(trait_ref, _)| trait_ref); let Normalized { value: trait_ref, obligations } = project::normalize_with_depth( self, @@ -3381,7 +3382,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested.extend(obligations); // Construct the nested `Field: Unsize>` predicate. - nested.push(tcx.predicate_for_trait_def( + nested.push(predicate_for_trait_def( + tcx, obligation.param_env, obligation.cause.clone(), obligation.predicate.def_id(), @@ -3416,7 +3418,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested.extend(obligations); // Construct the nested `T: Unsize` predicate. - nested.push(tcx.predicate_for_trait_def( + nested.push(predicate_for_trait_def( + tcx, obligation.param_env, obligation.cause.clone(), obligation.predicate.def_id(), @@ -3627,14 +3630,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // in fact unparameterized (or at least does not reference any // regions bound in the obligation). Still probably some // refactoring could make this nicer. - self.tcx() - .closure_trait_ref_and_return_type( - obligation.predicate.def_id(), - obligation.predicate.skip_binder().self_ty(), // (1) - closure_type, - util::TupleArgumentsFlag::No, - ) - .map_bound(|(trait_ref, _)| trait_ref) + closure_trait_ref_and_return_type( + self.tcx(), + obligation.predicate.def_id(), + obligation.predicate.skip_binder().self_ty(), // (1) + closure_type, + util::TupleArgumentsFlag::No, + ) + .map_bound(|(trait_ref, _)| trait_ref) } fn generator_trait_ref_unnormalized( @@ -3651,13 +3654,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // regions bound in the obligation). Still probably some // refactoring could make this nicer. - self.tcx() - .generator_trait_ref_and_outputs( - obligation.predicate.def_id(), - obligation.predicate.skip_binder().self_ty(), // (1) - gen_sig, - ) - .map_bound(|(trait_ref, ..)| trait_ref) + super::util::generator_trait_ref_and_outputs( + self.tcx(), + obligation.predicate.def_id(), + obligation.predicate.skip_binder().self_ty(), // (1) + gen_sig, + ) + .map_bound(|(trait_ref, ..)| trait_ref) } /// Returns the obligations that are implied by instantiating an diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 14cfe7cda4e28..8355239af87a4 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -548,123 +548,121 @@ pub fn predicate_for_trait_ref<'tcx>( Obligation { cause, param_env, recursion_depth, predicate: trait_ref.to_predicate() } } -impl<'tcx> TyCtxt<'tcx> { - pub fn predicate_for_trait_def( - self, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - trait_def_id: DefId, - recursion_depth: usize, - self_ty: Ty<'tcx>, - params: &[GenericArg<'tcx>], - ) -> PredicateObligation<'tcx> { - let trait_ref = - ty::TraitRef { def_id: trait_def_id, substs: self.mk_substs_trait(self_ty, params) }; - predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth) - } - - /// Casts a trait reference into a reference to one of its super - /// traits; returns `None` if `target_trait_def_id` is not a - /// supertrait. - pub fn upcast_choices( - self, - source_trait_ref: ty::PolyTraitRef<'tcx>, - target_trait_def_id: DefId, - ) -> Vec> { - if source_trait_ref.def_id() == target_trait_def_id { - return vec![source_trait_ref]; // Shortcut the most common case. - } +pub fn predicate_for_trait_def( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, + trait_def_id: DefId, + recursion_depth: usize, + self_ty: Ty<'tcx>, + params: &[GenericArg<'tcx>], +) -> PredicateObligation<'tcx> { + let trait_ref = + ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(self_ty, params) }; + predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth) +} - supertraits(self, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect() +/// Casts a trait reference into a reference to one of its super +/// traits; returns `None` if `target_trait_def_id` is not a +/// supertrait. +pub fn upcast_choices( + tcx: TyCtxt<'tcx>, + source_trait_ref: ty::PolyTraitRef<'tcx>, + target_trait_def_id: DefId, +) -> Vec> { + if source_trait_ref.def_id() == target_trait_def_id { + return vec![source_trait_ref]; // Shortcut the most common case. } - /// Given a trait `trait_ref`, returns the number of vtable entries - /// that come from `trait_ref`, excluding its supertraits. Used in - /// computing the vtable base for an upcast trait of a trait object. - pub fn count_own_vtable_entries(self, trait_ref: ty::PolyTraitRef<'tcx>) -> usize { - let mut entries = 0; - // Count number of methods and add them to the total offset. - // Skip over associated types and constants. - for trait_item in self.associated_items(trait_ref.def_id()) { - if trait_item.kind == ty::AssocKind::Method { - entries += 1; - } + supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect() +} + +/// Given a trait `trait_ref`, returns the number of vtable entries +/// that come from `trait_ref`, excluding its supertraits. Used in +/// computing the vtable base for an upcast trait of a trait object. +pub fn count_own_vtable_entries(tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> usize { + let mut entries = 0; + // Count number of methods and add them to the total offset. + // Skip over associated types and constants. + for trait_item in tcx.associated_items(trait_ref.def_id()) { + if trait_item.kind == ty::AssocKind::Method { + entries += 1; } - entries } + entries +} - /// Given an upcast trait object described by `object`, returns the - /// index of the method `method_def_id` (which should be part of - /// `object.upcast_trait_ref`) within the vtable for `object`. - pub fn get_vtable_index_of_object_method( - self, - object: &super::VtableObjectData<'tcx, N>, - method_def_id: DefId, - ) -> usize { - // Count number of methods preceding the one we are selecting and - // add them to the total offset. - // Skip over associated types and constants. - let mut entries = object.vtable_base; - for trait_item in self.associated_items(object.upcast_trait_ref.def_id()) { - if trait_item.def_id == method_def_id { - // The item with the ID we were given really ought to be a method. - assert_eq!(trait_item.kind, ty::AssocKind::Method); - return entries; - } - if trait_item.kind == ty::AssocKind::Method { - entries += 1; - } +/// Given an upcast trait object described by `object`, returns the +/// index of the method `method_def_id` (which should be part of +/// `object.upcast_trait_ref`) within the vtable for `object`. +pub fn get_vtable_index_of_object_method( + tcx: TyCtxt<'tcx>, + object: &super::VtableObjectData<'tcx, N>, + method_def_id: DefId, +) -> usize { + // Count number of methods preceding the one we are selecting and + // add them to the total offset. + // Skip over associated types and constants. + let mut entries = object.vtable_base; + for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()) { + if trait_item.def_id == method_def_id { + // The item with the ID we were given really ought to be a method. + assert_eq!(trait_item.kind, ty::AssocKind::Method); + return entries; + } + if trait_item.kind == ty::AssocKind::Method { + entries += 1; } - - bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id); } - pub fn closure_trait_ref_and_return_type( - self, - fn_trait_def_id: DefId, - self_ty: Ty<'tcx>, - sig: ty::PolyFnSig<'tcx>, - tuple_arguments: TupleArgumentsFlag, - ) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> { - let arguments_tuple = match tuple_arguments { - TupleArgumentsFlag::No => sig.skip_binder().inputs()[0], - TupleArgumentsFlag::Yes => self.intern_tup(sig.skip_binder().inputs()), - }; - let trait_ref = ty::TraitRef { - def_id: fn_trait_def_id, - substs: self.mk_substs_trait(self_ty, &[arguments_tuple.into()]), - }; - ty::Binder::bind((trait_ref, sig.skip_binder().output())) - } + bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id); +} - pub fn generator_trait_ref_and_outputs( - self, - fn_trait_def_id: DefId, - self_ty: Ty<'tcx>, - sig: ty::PolyGenSig<'tcx>, - ) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> { - let trait_ref = - ty::TraitRef { def_id: fn_trait_def_id, substs: self.mk_substs_trait(self_ty, &[]) }; - ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty)) - } +pub fn closure_trait_ref_and_return_type( + tcx: TyCtxt<'tcx>, + fn_trait_def_id: DefId, + self_ty: Ty<'tcx>, + sig: ty::PolyFnSig<'tcx>, + tuple_arguments: TupleArgumentsFlag, +) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> { + let arguments_tuple = match tuple_arguments { + TupleArgumentsFlag::No => sig.skip_binder().inputs()[0], + TupleArgumentsFlag::Yes => tcx.intern_tup(sig.skip_binder().inputs()), + }; + let trait_ref = ty::TraitRef { + def_id: fn_trait_def_id, + substs: tcx.mk_substs_trait(self_ty, &[arguments_tuple.into()]), + }; + ty::Binder::bind((trait_ref, sig.skip_binder().output())) +} - pub fn impl_is_default(self, node_item_def_id: DefId) -> bool { - match self.hir().as_local_hir_id(node_item_def_id) { - Some(hir_id) => { - let item = self.hir().expect_item(hir_id); - if let hir::ItemKind::Impl(_, _, defaultness, ..) = item.kind { - defaultness.is_default() - } else { - false - } +pub fn generator_trait_ref_and_outputs( + tcx: TyCtxt<'tcx>, + fn_trait_def_id: DefId, + self_ty: Ty<'tcx>, + sig: ty::PolyGenSig<'tcx>, +) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> { + let trait_ref = + ty::TraitRef { def_id: fn_trait_def_id, substs: tcx.mk_substs_trait(self_ty, &[]) }; + ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty)) +} + +pub fn impl_is_default(tcx: TyCtxt<'_>, node_item_def_id: DefId) -> bool { + match tcx.hir().as_local_hir_id(node_item_def_id) { + Some(hir_id) => { + let item = tcx.hir().expect_item(hir_id); + if let hir::ItemKind::Impl(_, _, defaultness, ..) = item.kind { + defaultness.is_default() + } else { + false } - None => self.impl_defaultness(node_item_def_id).is_default(), } + None => tcx.impl_defaultness(node_item_def_id).is_default(), } +} - pub fn impl_item_is_final(self, assoc_item: &ty::AssocItem) -> bool { - assoc_item.defaultness.is_final() && !self.impl_is_default(assoc_item.container.id()) - } +pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool { + assoc_item.defaultness.is_final() && !impl_is_default(tcx, assoc_item.container.id()) } pub enum TupleArgumentsFlag { diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 0db49183d1014..9be50d19a5030 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -411,7 +411,7 @@ fn resolve_associated_item<'tcx>( substs: rcvr_substs, }), traits::VtableObject(ref data) => { - let index = tcx.get_vtable_index_of_object_method(data, def_id); + let index = traits::get_vtable_index_of_object_method(tcx, data, def_id); Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs }) } traits::VtableBuiltin(..) => { diff --git a/src/librustc_mir/hair/pattern/const_to_pat.rs b/src/librustc_mir/hair/pattern/const_to_pat.rs index d4975df2e68cb..9631f8004f6a3 100644 --- a/src/librustc_mir/hair/pattern/const_to_pat.rs +++ b/src/librustc_mir/hair/pattern/const_to_pat.rs @@ -3,6 +3,7 @@ use crate::const_eval::const_variant_index; use rustc::infer::InferCtxt; use rustc::lint; use rustc::mir::Field; +use rustc::traits::predicate_for_trait_def; use rustc::traits::{ObligationCause, PredicateObligation}; use rustc::ty::{self, Ty, TyCtxt}; use rustc_hir as hir; @@ -129,7 +130,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // not *yet* implement `PartialEq`. So for now we leave this here. let ty_is_partial_eq: bool = { let partial_eq_trait_id = self.tcx().lang_items().eq_trait().unwrap(); - let obligation: PredicateObligation<'_> = self.tcx().predicate_for_trait_def( + let obligation: PredicateObligation<'_> = predicate_for_trait_def( + self.tcx(), self.param_env, ObligationCause::misc(self.span, self.id), partial_eq_trait_id, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 68cbd73a8aa9b..36ad6ea1bc995 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -544,7 +544,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // and almost never more than 3. By using a SmallVec we avoid an // allocation, at the (very small) cost of (occasionally) having to // shift subsequent elements down when removing the front element. - let mut queue: SmallVec<[_; 4]> = smallvec![self.tcx.predicate_for_trait_def( + let mut queue: SmallVec<[_; 4]> = smallvec![traits::predicate_for_trait_def( + self.tcx, self.fcx.param_env, cause, coerce_unsized_did, diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 83890cfce670c..636ea5b87d659 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -596,7 +596,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { target_trait_def_id: DefId, ) -> ty::PolyTraitRef<'tcx> { let upcast_trait_refs = - self.tcx.upcast_choices(source_trait_ref.clone(), target_trait_def_id); + traits::upcast_choices(self.tcx, source_trait_ref.clone(), target_trait_def_id); // must be exactly one trait ref or we'd get an ambig error etc if upcast_trait_refs.len() != 1 { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 430513ba803cc..647c56112b249 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1901,7 +1901,7 @@ fn check_specialization_validity<'tcx>( match parent_item { // Parent impl exists, and contains the parent item we're trying to specialize, but // doesn't mark it `default`. - Some(parent_item) if tcx.impl_item_is_final(&parent_item) => { + Some(parent_item) if traits::impl_item_is_final(tcx, &parent_item) => { Some(Err(parent_impl.def_id())) } @@ -1912,7 +1912,7 @@ fn check_specialization_validity<'tcx>( // grandparent. In that case, if parent is a `default impl`, inherited items use the // "defaultness" from the grandparent, else they are final. None => { - if tcx.impl_is_default(parent_impl.def_id()) { + if traits::impl_is_default(tcx, parent_impl.def_id()) { None } else { Some(Err(parent_impl.def_id())) @@ -2076,7 +2076,7 @@ fn check_impl_items_against_trait<'tcx>( .map(|node_item| !node_item.node.is_from_trait()) .unwrap_or(false); - if !is_implemented && !tcx.impl_is_default(impl_id) { + if !is_implemented && !traits::impl_is_default(tcx, impl_id) { if !trait_item.defaultness.has_value() { missing_items.push(trait_item); } else if associated_type_overridden { diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 6d97661e5272a..5a80b762f745a 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -7,6 +7,7 @@ use rustc::middle::lang_items::UnsizeTraitLangItem; use rustc::middle::region; use rustc::infer; +use rustc::traits::predicate_for_trait_def; use rustc::traits::{self, ObligationCause, TraitEngine}; use rustc::ty::adjustment::CoerceUnsizedInfo; use rustc::ty::util::CopyImplementationError; @@ -284,7 +285,8 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: DefId) { let mut fulfill_cx = TraitEngine::new(infcx.tcx); for field in coerced_fields { - let predicate = tcx.predicate_for_trait_def( + let predicate = predicate_for_trait_def( + tcx, param_env, cause.clone(), dispatch_from_dyn_trait, @@ -543,7 +545,8 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn // Register an obligation for `A: Trait`. let cause = traits::ObligationCause::misc(span, impl_hir_id); - let predicate = tcx.predicate_for_trait_def( + let predicate = predicate_for_trait_def( + tcx, param_env, cause, trait_def_id, From 73667af4445b4f86216c717f4d38ac980aa67903 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jan 2020 20:52:34 +0100 Subject: [PATCH 13/18] Move ty::wf to traits. --- src/librustc/traits/fulfill.rs | 3 ++- src/librustc/traits/mod.rs | 1 + src/librustc/traits/select.rs | 5 +++-- src/librustc/{ty => traits}/wf.rs | 2 +- src/librustc/ty/mod.rs | 1 - src/librustc_traits/implied_outlives_bounds.rs | 2 +- src/librustc_typeck/astconv.rs | 2 +- src/librustc_typeck/check/wfcheck.rs | 4 ++-- 8 files changed, 11 insertions(+), 9 deletions(-) rename src/librustc/{ty => traits}/wf.rs (99%) diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 614375287ba6e..b0b6994945c5f 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -9,6 +9,7 @@ use std::marker::PhantomData; use super::engine::{TraitEngine, TraitEngineExt}; use super::project; use super::select::SelectionContext; +use super::wf; use super::CodeAmbiguity; use super::CodeProjectionError; use super::CodeSelectionError; @@ -461,7 +462,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } ty::Predicate::WellFormed(ty) => { - match ty::wf::obligations( + match wf::obligations( self.selcx.infcx(), obligation.param_env, obligation.cause.body_id, diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index a2ccfc5de8abc..18653df14b618 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -18,6 +18,7 @@ mod select; mod specialize; mod structural_impls; mod util; +pub mod wf; use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::{InferCtxt, SuppressRegionErrors}; diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 3a9ed633740bf..1b1cb1b36e09a 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -12,6 +12,7 @@ use super::project; use super::project::{normalize_with_depth, Normalized, ProjectionCacheKey}; use super::util; use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; +use super::wf; use super::DerivedObligationCause; use super::Selection; use super::SelectionResult; @@ -738,7 +739,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::Predicate::WellFormed(ty) => match ty::wf::obligations( + ty::Predicate::WellFormed(ty) => match wf::obligations( self.infcx, obligation.param_env, obligation.cause.body_id, @@ -1154,7 +1155,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// to have a *lower* recursion_depth than the obligation used to create it. /// Projection sub-obligations may be returned from the projection cache, /// which results in obligations with an 'old' `recursion_depth`. - /// Additionally, methods like `ty::wf::obligations` and + /// Additionally, methods like `wf::obligations` and /// `InferCtxt.subtype_predicate` produce subobligations without /// taking in a 'parent' depth, causing the generated subobligations /// to have a `recursion_depth` of `0`. diff --git a/src/librustc/ty/wf.rs b/src/librustc/traits/wf.rs similarity index 99% rename from src/librustc/ty/wf.rs rename to src/librustc/traits/wf.rs index 60f5973339129..d033ab60f15db 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/traits/wf.rs @@ -514,7 +514,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // of whatever returned this exact `impl Trait`. // for named opaque `impl Trait` types we still need to check them - if super::is_impl_trait_defn(self.infcx.tcx, did).is_none() { + if ty::is_impl_trait_defn(self.infcx.tcx, did).is_none() { let obligations = self.nominal_obligations(did, substs); self.out.extend(obligations); } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6e7a4d6c53e29..858535cf4a47b 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -119,7 +119,6 @@ pub mod subst; pub mod trait_def; pub mod util; pub mod walk; -pub mod wf; mod context; mod diagnostics; diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs index 0e959cecaa9bb..40f821c29d366 100644 --- a/src/librustc_traits/implied_outlives_bounds.rs +++ b/src/librustc_traits/implied_outlives_bounds.rs @@ -5,11 +5,11 @@ use rustc::infer::canonical::{self, Canonical}; use rustc::infer::InferCtxt; use rustc::traits::query::outlives_bounds::OutlivesBound; use rustc::traits::query::{CanonicalTyGoal, Fallible, NoSolution}; +use rustc::traits::wf; use rustc::traits::FulfillmentContext; use rustc::traits::{TraitEngine, TraitEngineExt}; use rustc::ty::outlives::Component; use rustc::ty::query::Providers; -use rustc::ty::wf; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_hir as hir; use rustc_span::source_map::DUMMY_SP; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 82c97af1be4ed..5acaede2ee02e 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -15,8 +15,8 @@ use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc::traits; use rustc::traits::astconv_object_safety_violations; use rustc::traits::error_reporting::report_object_safety_error; +use rustc::traits::wf::object_region_bounds; use rustc::ty::subst::{self, InternalSubsts, Subst, SubstsRef}; -use rustc::ty::wf::object_region_bounds; use rustc::ty::{self, Const, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc::ty::{GenericParamDef, GenericParamDefKind}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 2da27d59829cf..f3a51fa33faa0 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -417,7 +417,7 @@ fn check_impl<'tcx>( 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( + let obligations = traits::wf::trait_obligations( fcx, fcx.param_env, fcx.body_id, @@ -596,7 +596,7 @@ fn check_where_clauses<'tcx, 'fcx>( let wf_obligations = predicates .predicates .iter() - .flat_map(|p| ty::wf::predicate_obligations(fcx, fcx.param_env, fcx.body_id, p, span)); + .flat_map(|p| traits::wf::predicate_obligations(fcx, fcx.param_env, fcx.body_id, p, span)); for obligation in wf_obligations.chain(default_obligations) { debug!("next obligation cause: {:?}", obligation.cause); From e905d5da93cfdbd49c4dc9c89a1537da726a8d35 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jan 2020 23:02:07 +0100 Subject: [PATCH 14/18] Move structural_match to rustc::traits. --- src/librustc/traits/mod.rs | 4 ++ .../{ty => traits}/structural_match.rs | 0 src/librustc/ty/mod.rs | 5 -- src/librustc_mir/hair/pattern/const_to_pat.rs | 12 ++-- src/librustc_typeck/collect.rs | 69 ++++++++++--------- 5 files changed, 45 insertions(+), 45 deletions(-) rename src/librustc/{ty => traits}/structural_match.rs (100%) diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 18653df14b618..3c49d1b6f36ea 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -17,6 +17,7 @@ pub mod query; mod select; mod specialize; mod structural_impls; +mod structural_match; mod util; pub mod wf; @@ -63,6 +64,9 @@ pub use self::specialize::find_associated_item; pub use self::specialize::specialization_graph::FutureCompatOverlapError; pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; pub use self::specialize::{specialization_graph, translate_substs, OverlapError}; +pub use self::structural_match::search_for_structural_match_violation; +pub use self::structural_match::type_marked_structural; +pub use self::structural_match::NonStructuralMatchTy; pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs}; pub use self::util::{expand_trait_aliases, TraitAliasExpander}; pub use self::util::{ diff --git a/src/librustc/ty/structural_match.rs b/src/librustc/traits/structural_match.rs similarity index 100% rename from src/librustc/ty/structural_match.rs rename to src/librustc/traits/structural_match.rs diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 858535cf4a47b..23e4309c1d337 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -87,10 +87,6 @@ pub use self::context::{ pub use self::instance::{Instance, InstanceDef}; -pub use self::structural_match::search_for_structural_match_violation; -pub use self::structural_match::type_marked_structural; -pub use self::structural_match::NonStructuralMatchTy; - pub use self::trait_def::TraitDef; pub use self::query::queries; @@ -124,7 +120,6 @@ mod context; mod diagnostics; mod instance; mod structural_impls; -mod structural_match; mod sty; // Data types diff --git a/src/librustc_mir/hair/pattern/const_to_pat.rs b/src/librustc_mir/hair/pattern/const_to_pat.rs index 9631f8004f6a3..75b25f03ca27b 100644 --- a/src/librustc_mir/hair/pattern/const_to_pat.rs +++ b/src/librustc_mir/hair/pattern/const_to_pat.rs @@ -4,7 +4,7 @@ use rustc::infer::InferCtxt; use rustc::lint; use rustc::mir::Field; use rustc::traits::predicate_for_trait_def; -use rustc::traits::{ObligationCause, PredicateObligation}; +use rustc::traits::{self, ObligationCause, PredicateObligation}; use rustc::ty::{self, Ty, TyCtxt}; use rustc_hir as hir; @@ -76,12 +76,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { fn search_for_structural_match_violation( &self, ty: Ty<'tcx>, - ) -> Option> { - ty::search_for_structural_match_violation(self.id, self.span, self.tcx(), ty) + ) -> Option> { + traits::search_for_structural_match_violation(self.id, self.span, self.tcx(), ty) } fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool { - ty::type_marked_structural(self.id, self.span, &self.infcx, ty) + traits::type_marked_structural(self.id, self.span, &self.infcx, ty) } fn to_pat(&mut self, cv: &'tcx ty::Const<'tcx>) -> Pat<'tcx> { @@ -105,8 +105,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { ); if let Some(non_sm_ty) = structural { let adt_def = match non_sm_ty { - ty::NonStructuralMatchTy::Adt(adt_def) => adt_def, - ty::NonStructuralMatchTy::Param => { + traits::NonStructuralMatchTy::Adt(adt_def) => adt_def, + traits::NonStructuralMatchTy::Param => { bug!("use of constant whose type is a parameter inside a pattern") } }; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1fefeaf720fcc..fb9e4ba5ce28e 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -23,6 +23,7 @@ use crate::middle::weak_lang_items; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc::mir::mono::Linkage; +use rustc::traits; use rustc::ty::query::Providers; use rustc::ty::subst::GenericArgKind; use rustc::ty::subst::{InternalSubsts, Subst}; @@ -1509,48 +1510,48 @@ fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } } - Node::GenericParam(param) => { - match ¶m.kind { - hir::GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty), - hir::GenericParamKind::Const { ty: ref hir_ty, .. } => { - let ty = icx.to_ty(hir_ty); - if !tcx.features().const_compare_raw_pointers { - let err = match ty.peel_refs().kind { - ty::FnPtr(_) => Some("function pointers"), - ty::RawPtr(_) => Some("raw pointers"), - _ => None, - }; - if let Some(unsupported_type) = err { - feature_gate::feature_err( - &tcx.sess.parse_sess, - sym::const_compare_raw_pointers, - hir_ty.span, - &format!( - "using {} as const generic parameters is unstable", - unsupported_type - ), - ) - .emit(); - }; - } - if ty::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty) - .is_some() - { - struct_span_err!( + Node::GenericParam(param) => match ¶m.kind { + hir::GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty), + hir::GenericParamKind::Const { ty: ref hir_ty, .. } => { + let ty = icx.to_ty(hir_ty); + if !tcx.features().const_compare_raw_pointers { + let err = match ty.peel_refs().kind { + ty::FnPtr(_) => Some("function pointers"), + ty::RawPtr(_) => Some("raw pointers"), + _ => None, + }; + if let Some(unsupported_type) = err { + feature_gate::feature_err( + &tcx.sess.parse_sess, + sym::const_compare_raw_pointers, + hir_ty.span, + &format!( + "using {} as const generic parameters is unstable", + unsupported_type + ), + ) + .emit(); + }; + } + if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty) + .is_some() + { + struct_span_err!( tcx.sess, hir_ty.span, E0741, "the types of const generic parameters must derive `PartialEq` and `Eq`", - ).span_label( + ) + .span_label( hir_ty.span, format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty), - ).emit(); - } - ty + ) + .emit(); } - x => bug!("unexpected non-type Node::GenericParam: {:?}", x), + ty } - } + x => bug!("unexpected non-type Node::GenericParam: {:?}", x), + }, x => { bug!("unexpected sort of node in type_of_def_id(): {:?}", x); From 24d09c7c1b454dae43adc39827311d741dcbf896 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jan 2020 23:08:02 +0100 Subject: [PATCH 15/18] Move free_region_map to rustc::ty. --- src/librustc/infer/opaque_types/mod.rs | 2 +- src/librustc/infer/outlives/env.rs | 2 +- src/librustc/infer/outlives/mod.rs | 1 - src/librustc/middle/free_region.rs | 2 +- src/librustc/ty/context.rs | 2 +- src/librustc/{infer/outlives => ty}/free_region_map.rs | 0 src/librustc/ty/mod.rs | 1 + .../borrow_check/type_check/free_region_relations.rs | 2 +- 8 files changed, 6 insertions(+), 6 deletions(-) rename src/librustc/{infer/outlives => ty}/free_region_map.rs (100%) diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 834b8e8e72e02..10d5fdf30e3ec 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -1,9 +1,9 @@ use crate::infer::error_reporting::{note_and_explain_free_region, note_and_explain_region}; -use crate::infer::outlives::free_region_map::FreeRegionRelations; use crate::infer::{self, InferCtxt, InferOk, TypeVariableOrigin, TypeVariableOriginKind}; use crate::middle::region; use crate::traits::{self, PredicateObligation}; use crate::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor}; +use crate::ty::free_region_map::FreeRegionRelations; use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef}; use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt}; use errors::DiagnosticBuilder; diff --git a/src/librustc/infer/outlives/env.rs b/src/librustc/infer/outlives/env.rs index 130cffe502287..ee2e629c2fcd2 100644 --- a/src/librustc/infer/outlives/env.rs +++ b/src/librustc/infer/outlives/env.rs @@ -1,6 +1,6 @@ -use crate::infer::outlives::free_region_map::FreeRegionMap; use crate::infer::{GenericKind, InferCtxt}; use crate::traits::query::outlives_bounds::{self, OutlivesBound}; +use crate::ty::free_region_map::FreeRegionMap; use crate::ty::{self, Ty}; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; diff --git a/src/librustc/infer/outlives/mod.rs b/src/librustc/infer/outlives/mod.rs index e421d6fb6922f..6fc72470c9fb7 100644 --- a/src/librustc/infer/outlives/mod.rs +++ b/src/librustc/infer/outlives/mod.rs @@ -1,6 +1,5 @@ //! Various code related to computing outlives relations. pub mod env; -pub mod free_region_map; pub mod obligations; pub mod verify; diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index 253e00f9e4db5..355f949b87008 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -3,8 +3,8 @@ //! or explicit bounds. In that case, we track the bounds using the `TransitiveRelation` type, //! and use that to decide when one free region outlives another, and so forth. -use crate::infer::outlives::free_region_map::{FreeRegionMap, FreeRegionRelations}; use crate::middle::region; +use crate::ty::free_region_map::{FreeRegionMap, FreeRegionRelations}; use crate::ty::{self, Region, TyCtxt}; use rustc_hir::def_id::DefId; diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index a2e5edb67fc67..17f5b98ab208b 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -8,7 +8,6 @@ use crate::hir::map as hir_map; use crate::hir::map::DefPathHash; use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; -use crate::infer::outlives::free_region_map::FreeRegionMap; use crate::lint::{self, Lint}; use crate::middle; use crate::middle::cstore::CrateStoreDyn; @@ -26,6 +25,7 @@ use crate::session::config::{BorrowckMode, OutputFilenames}; use crate::session::Session; use crate::traits; use crate::traits::{Clause, Clauses, Goal, GoalKind, Goals}; +use crate::ty::free_region_map::FreeRegionMap; use crate::ty::layout::{LayoutDetails, TargetDataLayout, VariantIdx}; use crate::ty::query; use crate::ty::steal::Steal; diff --git a/src/librustc/infer/outlives/free_region_map.rs b/src/librustc/ty/free_region_map.rs similarity index 100% rename from src/librustc/infer/outlives/free_region_map.rs rename to src/librustc/ty/free_region_map.rs diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 23e4309c1d337..5457516a6a272 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -103,6 +103,7 @@ pub mod error; pub mod fast_reject; pub mod flags; pub mod fold; +pub mod free_region_map; pub mod inhabitedness; pub mod layout; pub mod normalize_erasing_regions; diff --git a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs index 0e4801b88d87e..f0dc94f417c1e 100644 --- a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs +++ b/src/librustc_mir/borrow_check/type_check/free_region_relations.rs @@ -1,10 +1,10 @@ use rustc::infer::canonical::QueryRegionConstraints; -use rustc::infer::outlives::free_region_map::FreeRegionRelations; use rustc::infer::region_constraints::GenericKind; use rustc::infer::InferCtxt; use rustc::mir::ConstraintCategory; use rustc::traits::query::outlives_bounds::{self, OutlivesBound}; use rustc::traits::query::type_op::{self, TypeOp}; +use rustc::ty::free_region_map::FreeRegionRelations; use rustc::ty::{self, RegionVid, Ty}; use rustc_data_structures::transitive_relation::TransitiveRelation; use rustc_span::DUMMY_SP; From 86ec4b5f8508854321e9438902bbbcbbcd5d9a7f Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jan 2020 23:28:45 +0100 Subject: [PATCH 16/18] Move required_region_bounds to rustc::infer::opaque_types. --- src/librustc/infer/opaque_types/mod.rs | 69 +++++++++++++++++++++++++- src/librustc/traits/wf.rs | 5 +- src/librustc/ty/util.rs | 64 ------------------------ 3 files changed, 70 insertions(+), 68 deletions(-) diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 10d5fdf30e3ec..a22ed94096132 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -350,7 +350,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { debug!("constrain_opaque_type: bounds={:#?}", bounds); let opaque_type = tcx.mk_opaque(def_id, opaque_defn.substs); - let required_region_bounds = tcx.required_region_bounds(opaque_type, bounds.predicates); + let required_region_bounds = + required_region_bounds(tcx, opaque_type, bounds.predicates); debug_assert!(!required_region_bounds.is_empty()); for required_region in required_region_bounds { @@ -1133,7 +1134,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { debug!("instantiate_opaque_types: bounds={:?}", bounds); - let required_region_bounds = tcx.required_region_bounds(ty, bounds.predicates.clone()); + let required_region_bounds = required_region_bounds(tcx, ty, bounds.predicates.clone()); debug!("instantiate_opaque_types: required_region_bounds={:?}", required_region_bounds); // Make sure that we are in fact defining the *entire* type @@ -1228,3 +1229,67 @@ pub fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: DefId, opaque_hir_id: hir ); res } + +/// Given a set of predicates that apply to an object type, returns +/// the region bounds that the (erased) `Self` type must +/// outlive. Precisely *because* the `Self` type is erased, the +/// parameter `erased_self_ty` must be supplied to indicate what type +/// has been used to represent `Self` in the predicates +/// themselves. This should really be a unique type; `FreshTy(0)` is a +/// popular choice. +/// +/// N.B., in some cases, particularly around higher-ranked bounds, +/// this function returns a kind of conservative approximation. +/// That is, all regions returned by this function are definitely +/// required, but there may be other region bounds that are not +/// returned, as well as requirements like `for<'a> T: 'a`. +/// +/// Requires that trait definitions have been processed so that we can +/// elaborate predicates and walk supertraits. +// +// FIXME: callers may only have a `&[Predicate]`, not a `Vec`, so that's +// what this code should accept. +crate fn required_region_bounds( + tcx: TyCtxt<'tcx>, + erased_self_ty: Ty<'tcx>, + predicates: Vec>, +) -> Vec> { + debug!( + "required_region_bounds(erased_self_ty={:?}, predicates={:?})", + erased_self_ty, predicates + ); + + assert!(!erased_self_ty.has_escaping_bound_vars()); + + traits::elaborate_predicates(tcx, predicates) + .filter_map(|predicate| { + match predicate { + ty::Predicate::Projection(..) + | ty::Predicate::Trait(..) + | ty::Predicate::Subtype(..) + | ty::Predicate::WellFormed(..) + | ty::Predicate::ObjectSafe(..) + | ty::Predicate::ClosureKind(..) + | ty::Predicate::RegionOutlives(..) + | ty::Predicate::ConstEvaluatable(..) => None, + ty::Predicate::TypeOutlives(predicate) => { + // Search for a bound of the form `erased_self_ty + // : 'a`, but be wary of something like `for<'a> + // erased_self_ty : 'a` (we interpret a + // higher-ranked bound like that as 'static, + // though at present the code in `fulfill.rs` + // considers such bounds to be unsatisfiable, so + // it's kind of a moot point since you could never + // construct such an object, but this seems + // correct even if that code changes). + let ty::OutlivesPredicate(ref t, ref r) = predicate.skip_binder(); + if t == &erased_self_ty && !r.has_escaping_bound_vars() { + Some(*r) + } else { + None + } + } + } + }) + .collect() +} diff --git a/src/librustc/traits/wf.rs b/src/librustc/traits/wf.rs index d033ab60f15db..551f8fde12b18 100644 --- a/src/librustc/traits/wf.rs +++ b/src/librustc/traits/wf.rs @@ -1,3 +1,4 @@ +use crate::infer::opaque_types::required_region_bounds; use crate::infer::InferCtxt; use crate::middle::lang_items; use crate::traits::{self, AssocTypeBoundData}; @@ -668,7 +669,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { /// from the declarations of `SomeTrait`, `Send`, and friends -- if /// they declare `trait SomeTrait : 'static`, for example, then /// `'static` would appear in the list. The hard work is done by -/// `ty::required_region_bounds`, see that for more information. +/// `infer::required_region_bounds`, see that for more information. pub fn object_region_bounds<'tcx>( tcx: TyCtxt<'tcx>, existential_predicates: ty::Binder<&'tcx ty::List>>, @@ -689,7 +690,7 @@ pub fn object_region_bounds<'tcx>( }) .collect(); - tcx.required_region_bounds(open_ty, predicates) + required_region_bounds(tcx, open_ty, predicates) } /// Find the span of a generic bound affecting an associated type. diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index e0f4f2616017d..ee99176dc47f5 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -393,70 +393,6 @@ impl<'tcx> TyCtxt<'tcx> { (a, b) } - /// Given a set of predicates that apply to an object type, returns - /// the region bounds that the (erased) `Self` type must - /// outlive. Precisely *because* the `Self` type is erased, the - /// parameter `erased_self_ty` must be supplied to indicate what type - /// has been used to represent `Self` in the predicates - /// themselves. This should really be a unique type; `FreshTy(0)` is a - /// popular choice. - /// - /// N.B., in some cases, particularly around higher-ranked bounds, - /// this function returns a kind of conservative approximation. - /// That is, all regions returned by this function are definitely - /// required, but there may be other region bounds that are not - /// returned, as well as requirements like `for<'a> T: 'a`. - /// - /// Requires that trait definitions have been processed so that we can - /// elaborate predicates and walk supertraits. - // - // FIXME: callers may only have a `&[Predicate]`, not a `Vec`, so that's - // what this code should accept. - pub fn required_region_bounds( - self, - erased_self_ty: Ty<'tcx>, - predicates: Vec>, - ) -> Vec> { - debug!( - "required_region_bounds(erased_self_ty={:?}, predicates={:?})", - erased_self_ty, predicates - ); - - assert!(!erased_self_ty.has_escaping_bound_vars()); - - traits::elaborate_predicates(self, predicates) - .filter_map(|predicate| { - match predicate { - ty::Predicate::Projection(..) - | ty::Predicate::Trait(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::RegionOutlives(..) - | ty::Predicate::ConstEvaluatable(..) => None, - ty::Predicate::TypeOutlives(predicate) => { - // Search for a bound of the form `erased_self_ty - // : 'a`, but be wary of something like `for<'a> - // erased_self_ty : 'a` (we interpret a - // higher-ranked bound like that as 'static, - // though at present the code in `fulfill.rs` - // considers such bounds to be unsatisfiable, so - // it's kind of a moot point since you could never - // construct such an object, but this seems - // correct even if that code changes). - let ty::OutlivesPredicate(ref t, ref r) = predicate.skip_binder(); - if t == &erased_self_ty && !r.has_escaping_bound_vars() { - Some(*r) - } else { - None - } - } - } - }) - .collect() - } - /// Calculate the destructor of a given type. pub fn calculate_dtor( self, From f629baf96cd0dd741f4490e782a72b2ff40b27fd Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jan 2020 23:43:45 +0100 Subject: [PATCH 17/18] Move magic traits queries to rustc::traits::drop. --- src/librustc/traits/drop.rs | 202 +++++++++++++++++++++++ src/librustc/traits/mod.rs | 2 + src/librustc/ty/mod.rs | 1 - src/librustc/ty/util.rs | 199 +--------------------- src/librustc_lint/builtin.rs | 3 +- src/librustc_passes/stability.rs | 3 +- src/librustc_typeck/coherence/builtin.rs | 4 +- 7 files changed, 211 insertions(+), 203 deletions(-) create mode 100644 src/librustc/traits/drop.rs diff --git a/src/librustc/traits/drop.rs b/src/librustc/traits/drop.rs new file mode 100644 index 0000000000000..08c3a77bf3aca --- /dev/null +++ b/src/librustc/traits/drop.rs @@ -0,0 +1,202 @@ +//! Miscellaneous type-system utilities that are too small to deserve their own modules. + +use crate::middle::lang_items; +use crate::traits::{self, ObligationCause}; +use crate::ty::util::NeedsDrop; +use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; + +use rustc_hir as hir; +use rustc_span::DUMMY_SP; + +#[derive(Clone)] +pub enum CopyImplementationError<'tcx> { + InfrigingFields(Vec<&'tcx ty::FieldDef>), + NotAnAdt, + HasDestructor, +} + +pub fn can_type_implement_copy( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + self_type: Ty<'tcx>, +) -> Result<(), CopyImplementationError<'tcx>> { + // FIXME: (@jroesch) float this code up + tcx.infer_ctxt().enter(|infcx| { + let (adt, substs) = match self_type.kind { + // These types used to have a builtin impl. + // Now libcore provides that impl. + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Ref(_, _, hir::Mutability::Not) => return Ok(()), + + ty::Adt(adt, substs) => (adt, substs), + + _ => return Err(CopyImplementationError::NotAnAdt), + }; + + let mut infringing = Vec::new(); + for variant in &adt.variants { + for field in &variant.fields { + let ty = field.ty(tcx, substs); + if ty.references_error() { + continue; + } + let span = tcx.def_span(field.did); + let cause = ObligationCause { span, ..ObligationCause::dummy() }; + let ctx = traits::FulfillmentContext::new(); + match traits::fully_normalize(&infcx, ctx, cause, param_env, &ty) { + Ok(ty) => { + if !infcx.type_is_copy_modulo_regions(param_env, ty, span) { + infringing.push(field); + } + } + Err(errors) => { + infcx.report_fulfillment_errors(&errors, None, false); + } + }; + } + } + if !infringing.is_empty() { + return Err(CopyImplementationError::InfrigingFields(infringing)); + } + if adt.has_dtor(tcx) { + return Err(CopyImplementationError::HasDestructor); + } + + Ok(()) + }) +} + +fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + is_item_raw(tcx, query, lang_items::CopyTraitLangItem) +} + +fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + is_item_raw(tcx, query, lang_items::SizedTraitLangItem) +} + +fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + is_item_raw(tcx, query, lang_items::FreezeTraitLangItem) +} + +fn is_item_raw<'tcx>( + tcx: TyCtxt<'tcx>, + query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, + item: lang_items::LangItem, +) -> bool { + let (param_env, ty) = query.into_parts(); + let trait_def_id = tcx.require_lang_item(item, None); + tcx.infer_ctxt().enter(|infcx| { + traits::type_known_to_meet_bound_modulo_regions( + &infcx, + param_env, + ty, + trait_def_id, + DUMMY_SP, + ) + }) +} + +fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> NeedsDrop { + let (param_env, ty) = query.into_parts(); + + let needs_drop = |ty: Ty<'tcx>| -> bool { tcx.needs_drop_raw(param_env.and(ty)).0 }; + + assert!(!ty.needs_infer()); + + NeedsDrop(match ty.kind { + // Fast-path for primitive types + ty::Infer(ty::FreshIntTy(_)) + | ty::Infer(ty::FreshFloatTy(_)) + | ty::Bool + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Never + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Char + | ty::GeneratorWitness(..) + | ty::RawPtr(_) + | ty::Ref(..) + | ty::Str => false, + + // Foreign types can never have destructors + ty::Foreign(..) => false, + + // `ManuallyDrop` doesn't have a destructor regardless of field types. + ty::Adt(def, _) if Some(def.did) == tcx.lang_items().manually_drop() => false, + + // Issue #22536: We first query `is_copy_modulo_regions`. It sees a + // normalized version of the type, and therefore will definitely + // know whether the type implements Copy (and thus needs no + // cleanup/drop/zeroing) ... + _ if ty.is_copy_modulo_regions(tcx, param_env, DUMMY_SP) => false, + + // ... (issue #22536 continued) but as an optimization, still use + // prior logic of asking for the structural "may drop". + + // FIXME(#22815): Note that this is a conservative heuristic; + // it may report that the type "may drop" when actual type does + // not actually have a destructor associated with it. But since + // the type absolutely did not have the `Copy` bound attached + // (see above), it is sound to treat it as having a destructor. + + // User destructors are the only way to have concrete drop types. + ty::Adt(def, _) if def.has_dtor(tcx) => true, + + // Can refer to a type which may drop. + // FIXME(eddyb) check this against a ParamEnv. + ty::Dynamic(..) + | ty::Projection(..) + | ty::Param(_) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Opaque(..) + | ty::Infer(_) + | ty::Error => true, + + ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), + + // Zero-length arrays never contain anything to drop. + ty::Array(_, len) if len.try_eval_usize(tcx, param_env) == Some(0) => false, + + // Structural recursion. + ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty), + + ty::Closure(def_id, ref substs) => { + substs.as_closure().upvar_tys(def_id, tcx).any(needs_drop) + } + + // Pessimistically assume that all generators will require destructors + // as we don't know if a destructor is a noop or not until after the MIR + // state transformation pass + ty::Generator(..) => true, + + ty::Tuple(..) => ty.tuple_fields().any(needs_drop), + + // unions don't have destructors because of the child types, + // only if they manually implement `Drop` (handled above). + ty::Adt(def, _) if def.is_union() => false, + + ty::Adt(def, substs) => def + .variants + .iter() + .any(|variant| variant.fields.iter().any(|field| needs_drop(field.ty(tcx, substs)))), + }) +} + +pub fn provide(providers: &mut ty::query::Providers<'_>) { + *providers = ty::query::Providers { + is_copy_raw, + is_sized_raw, + is_freeze_raw, + needs_drop_raw, + ..*providers + }; +} diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 3c49d1b6f36ea..11473dc2a3a6d 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -7,6 +7,7 @@ pub mod auto_trait; mod chalk_fulfill; pub mod codegen; mod coherence; +pub mod drop; mod engine; pub mod error_reporting; mod fulfill; @@ -1243,6 +1244,7 @@ impl<'tcx> TraitObligation<'tcx> { } pub fn provide(providers: &mut ty::query::Providers<'_>) { + drop::provide(providers); *providers = ty::query::Providers { is_object_safe: object_safety::is_object_safe_provider, specialization_graph_of: specialize::specialization_graph_provider, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 5457516a6a272..7cca12308e65f 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -3318,7 +3318,6 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { context::provide(providers); erase_regions::provide(providers); layout::provide(providers); - util::provide(providers); constness::provide(providers); *providers = ty::query::Providers { asyncness, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index ee99176dc47f5..aa93f35661a28 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -2,9 +2,7 @@ use crate::hir::map::DefPathData; use crate::ich::NodeIdHashingMode; -use crate::middle::lang_items; use crate::mir::interpret::{sign_extend, truncate}; -use crate::traits::{self, ObligationCause}; use crate::ty::layout::{Integer, IntegerExt}; use crate::ty::query::TyCtxtAt; use crate::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef}; @@ -18,7 +16,7 @@ use rustc_hir::def_id::DefId; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::HashStable; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use std::{cmp, fmt}; use syntax::ast; use syntax::attr::{self, SignedInt, UnsignedInt}; @@ -122,13 +120,6 @@ impl IntTypeExt for attr::IntType { } } -#[derive(Clone)] -pub enum CopyImplementationError<'tcx> { - InfrigingFields(Vec<&'tcx ty::FieldDef>), - NotAnAdt, - HasDestructor, -} - /// Describes whether a type is representable. For types that are not /// representable, 'SelfRecursive' and 'ContainsRecursive' are used to /// distinguish between types that are recursive with themselves and types that @@ -144,65 +135,6 @@ pub enum Representability { SelfRecursive(Vec), } -impl<'tcx> ty::ParamEnv<'tcx> { - pub fn can_type_implement_copy( - self, - tcx: TyCtxt<'tcx>, - self_type: Ty<'tcx>, - ) -> Result<(), CopyImplementationError<'tcx>> { - // FIXME: (@jroesch) float this code up - tcx.infer_ctxt().enter(|infcx| { - let (adt, substs) = match self_type.kind { - // These types used to have a builtin impl. - // Now libcore provides that impl. - ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::Char - | ty::RawPtr(..) - | ty::Never - | ty::Ref(_, _, hir::Mutability::Not) => return Ok(()), - - ty::Adt(adt, substs) => (adt, substs), - - _ => return Err(CopyImplementationError::NotAnAdt), - }; - - let mut infringing = Vec::new(); - for variant in &adt.variants { - for field in &variant.fields { - let ty = field.ty(tcx, substs); - if ty.references_error() { - continue; - } - let span = tcx.def_span(field.did); - let cause = ObligationCause { span, ..ObligationCause::dummy() }; - let ctx = traits::FulfillmentContext::new(); - match traits::fully_normalize(&infcx, ctx, cause, self, &ty) { - Ok(ty) => { - if !infcx.type_is_copy_modulo_regions(self, ty, span) { - infringing.push(field); - } - } - Err(errors) => { - infcx.report_fulfillment_errors(&errors, None, false); - } - }; - } - } - if !infringing.is_empty() { - return Err(CopyImplementationError::InfrigingFields(infringing)); - } - if adt.has_dtor(tcx) { - return Err(CopyImplementationError::HasDestructor); - } - - Ok(()) - }) - } -} - impl<'tcx> TyCtxt<'tcx> { /// Creates a hash of the type `Ty` which will be the same no matter what crate /// context it's calculated within. This is used by the `type_id` intrinsic. @@ -942,128 +874,9 @@ impl<'tcx> ty::TyS<'tcx> { } } -fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - is_item_raw(tcx, query, lang_items::CopyTraitLangItem) -} - -fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - is_item_raw(tcx, query, lang_items::SizedTraitLangItem) -} - -fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { - is_item_raw(tcx, query, lang_items::FreezeTraitLangItem) -} - -fn is_item_raw<'tcx>( - tcx: TyCtxt<'tcx>, - query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, - item: lang_items::LangItem, -) -> bool { - let (param_env, ty) = query.into_parts(); - let trait_def_id = tcx.require_lang_item(item, None); - tcx.infer_ctxt().enter(|infcx| { - traits::type_known_to_meet_bound_modulo_regions( - &infcx, - param_env, - ty, - trait_def_id, - DUMMY_SP, - ) - }) -} - #[derive(Clone, HashStable)] pub struct NeedsDrop(pub bool); -fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> NeedsDrop { - let (param_env, ty) = query.into_parts(); - - let needs_drop = |ty: Ty<'tcx>| -> bool { tcx.needs_drop_raw(param_env.and(ty)).0 }; - - assert!(!ty.needs_infer()); - - NeedsDrop(match ty.kind { - // Fast-path for primitive types - ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) - | ty::Bool - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Never - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Char - | ty::GeneratorWitness(..) - | ty::RawPtr(_) - | ty::Ref(..) - | ty::Str => false, - - // Foreign types can never have destructors - ty::Foreign(..) => false, - - // `ManuallyDrop` doesn't have a destructor regardless of field types. - ty::Adt(def, _) if Some(def.did) == tcx.lang_items().manually_drop() => false, - - // Issue #22536: We first query `is_copy_modulo_regions`. It sees a - // normalized version of the type, and therefore will definitely - // know whether the type implements Copy (and thus needs no - // cleanup/drop/zeroing) ... - _ if ty.is_copy_modulo_regions(tcx, param_env, DUMMY_SP) => false, - - // ... (issue #22536 continued) but as an optimization, still use - // prior logic of asking for the structural "may drop". - - // FIXME(#22815): Note that this is a conservative heuristic; - // it may report that the type "may drop" when actual type does - // not actually have a destructor associated with it. But since - // the type absolutely did not have the `Copy` bound attached - // (see above), it is sound to treat it as having a destructor. - - // User destructors are the only way to have concrete drop types. - ty::Adt(def, _) if def.has_dtor(tcx) => true, - - // Can refer to a type which may drop. - // FIXME(eddyb) check this against a ParamEnv. - ty::Dynamic(..) - | ty::Projection(..) - | ty::Param(_) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Opaque(..) - | ty::Infer(_) - | ty::Error => true, - - ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), - - // Zero-length arrays never contain anything to drop. - ty::Array(_, len) if len.try_eval_usize(tcx, param_env) == Some(0) => false, - - // Structural recursion. - ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty), - - ty::Closure(def_id, ref substs) => { - substs.as_closure().upvar_tys(def_id, tcx).any(needs_drop) - } - - // Pessimistically assume that all generators will require destructors - // as we don't know if a destructor is a noop or not until after the MIR - // state transformation pass - ty::Generator(..) => true, - - ty::Tuple(..) => ty.tuple_fields().any(needs_drop), - - // unions don't have destructors because of the child types, - // only if they manually implement `Drop` (handled above). - ty::Adt(def, _) if def.is_union() => false, - - ty::Adt(def, substs) => def - .variants - .iter() - .any(|variant| variant.fields.iter().any(|field| needs_drop(field.ty(tcx, substs)))), - }) -} - pub enum ExplicitSelf<'tcx> { ByValue, ByReference(ty::Region<'tcx>, hir::Mutability), @@ -1112,13 +925,3 @@ impl<'tcx> ExplicitSelf<'tcx> { } } } - -pub fn provide(providers: &mut ty::query::Providers<'_>) { - *providers = ty::query::Providers { - is_copy_raw, - is_sized_raw, - is_freeze_raw, - needs_drop_raw, - ..*providers - }; -} diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 59b87afe2160b..e251e6d6aea78 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -27,6 +27,7 @@ use lint::{EarlyContext, EarlyLintPass, LateLintPass, LintPass}; use lint::{LateContext, LintArray, LintContext}; use rustc::lint; use rustc::lint::FutureIncompatibleInfo; +use rustc::traits::drop::can_type_implement_copy; use rustc::ty::{self, layout::VariantIdx, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashSet; use rustc_feature::Stability; @@ -555,7 +556,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations { if ty.is_copy_modulo_regions(cx.tcx, param_env, item.span) { return; } - if param_env.can_type_implement_copy(cx.tcx, ty).is_ok() { + if can_type_implement_copy(cx.tcx, param_env, ty).is_ok() { cx.span_lint( MISSING_COPY_IMPLEMENTATIONS, item.span, diff --git a/src/librustc_passes/stability.rs b/src/librustc_passes/stability.rs index 4c5b57791c552..35ef7ec148fed 100644 --- a/src/librustc_passes/stability.rs +++ b/src/librustc_passes/stability.rs @@ -6,6 +6,7 @@ use rustc::lint; use rustc::middle::privacy::AccessLevels; use rustc::middle::stability::{DeprecationEntry, Index}; use rustc::session::Session; +use rustc::traits::drop::can_type_implement_copy; use rustc::ty::query::Providers; use rustc::ty::TyCtxt; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -488,7 +489,7 @@ impl Visitor<'tcx> for Checker<'tcx> { .emit(); } else { let param_env = self.tcx.param_env(def_id); - if !param_env.can_type_implement_copy(self.tcx, ty).is_ok() { + if !can_type_implement_copy(self.tcx, param_env, ty).is_ok() { feature_err( &self.tcx.sess.parse_sess, sym::untagged_unions, diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 5a80b762f745a..1bb512e350a61 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -7,10 +7,10 @@ use rustc::middle::lang_items::UnsizeTraitLangItem; use rustc::middle::region; use rustc::infer; +use rustc::traits::drop::{can_type_implement_copy, CopyImplementationError}; use rustc::traits::predicate_for_trait_def; use rustc::traits::{self, ObligationCause, TraitEngine}; use rustc::ty::adjustment::CoerceUnsizedInfo; -use rustc::ty::util::CopyImplementationError; use rustc::ty::TypeFoldable; use rustc::ty::{self, Ty, TyCtxt}; @@ -92,7 +92,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: DefId) { debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type); - match param_env.can_type_implement_copy(tcx, self_type) { + match can_type_implement_copy(tcx, param_env, self_type) { Ok(()) => {} Err(CopyImplementationError::InfrigingFields(fields)) => { let item = tcx.hir().expect_item(impl_hir_id); From 700ac84eae77e95bbc6e8276a4f4ad102d6e83e5 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 7 Jan 2020 19:36:50 +0100 Subject: [PATCH 18/18] Rename traits::drop -> traits::misc. --- src/librustc/traits/{drop.rs => misc.rs} | 0 src/librustc/traits/mod.rs | 4 ++-- src/librustc_lint/builtin.rs | 2 +- src/librustc_passes/stability.rs | 2 +- src/librustc_typeck/coherence/builtin.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename src/librustc/traits/{drop.rs => misc.rs} (100%) diff --git a/src/librustc/traits/drop.rs b/src/librustc/traits/misc.rs similarity index 100% rename from src/librustc/traits/drop.rs rename to src/librustc/traits/misc.rs diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 11473dc2a3a6d..2d3160dc3e51a 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -7,10 +7,10 @@ pub mod auto_trait; mod chalk_fulfill; pub mod codegen; mod coherence; -pub mod drop; mod engine; pub mod error_reporting; mod fulfill; +pub mod misc; mod object_safety; mod on_unimplemented; mod project; @@ -1244,7 +1244,7 @@ impl<'tcx> TraitObligation<'tcx> { } pub fn provide(providers: &mut ty::query::Providers<'_>) { - drop::provide(providers); + misc::provide(providers); *providers = ty::query::Providers { is_object_safe: object_safety::is_object_safe_provider, specialization_graph_of: specialize::specialization_graph_provider, diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index e251e6d6aea78..c2e20d5cf758e 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -27,7 +27,7 @@ use lint::{EarlyContext, EarlyLintPass, LateLintPass, LintPass}; use lint::{LateContext, LintArray, LintContext}; use rustc::lint; use rustc::lint::FutureIncompatibleInfo; -use rustc::traits::drop::can_type_implement_copy; +use rustc::traits::misc::can_type_implement_copy; use rustc::ty::{self, layout::VariantIdx, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashSet; use rustc_feature::Stability; diff --git a/src/librustc_passes/stability.rs b/src/librustc_passes/stability.rs index 35ef7ec148fed..68e2bc5326141 100644 --- a/src/librustc_passes/stability.rs +++ b/src/librustc_passes/stability.rs @@ -6,7 +6,7 @@ use rustc::lint; use rustc::middle::privacy::AccessLevels; use rustc::middle::stability::{DeprecationEntry, Index}; use rustc::session::Session; -use rustc::traits::drop::can_type_implement_copy; +use rustc::traits::misc::can_type_implement_copy; use rustc::ty::query::Providers; use rustc::ty::TyCtxt; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 1bb512e350a61..eb1ea679040a8 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -7,7 +7,7 @@ use rustc::middle::lang_items::UnsizeTraitLangItem; use rustc::middle::region; use rustc::infer; -use rustc::traits::drop::{can_type_implement_copy, CopyImplementationError}; +use rustc::traits::misc::{can_type_implement_copy, CopyImplementationError}; use rustc::traits::predicate_for_trait_def; use rustc::traits::{self, ObligationCause, TraitEngine}; use rustc::ty::adjustment::CoerceUnsizedInfo;