From d99805982b57eb7827da2b66a21121b4c76b41e9 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 26 Jul 2021 16:57:18 +0000 Subject: [PATCH 01/13] Move opaque type cache into `InferCtxt` --- compiler/rustc_infer/src/infer/mod.rs | 19 +++++ .../rustc_infer/src/infer/opaque_types.rs | 70 ++++++++++++++++ .../rustc_trait_selection/src/opaque_types.rs | 83 ++----------------- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 9 +- compiler/rustc_typeck/src/check/inherited.rs | 20 +---- compiler/rustc_typeck/src/check/regionck.rs | 5 +- compiler/rustc_typeck/src/check/writeback.rs | 3 +- 7 files changed, 102 insertions(+), 107 deletions(-) create mode 100644 compiler/rustc_infer/src/infer/opaque_types.rs diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index f0d63f512fcbc..62bfe03427e1c 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -4,6 +4,7 @@ pub use self::RegionVariableOrigin::*; pub use self::SubregionOrigin::*; pub use self::ValuePairs::*; +use self::opaque_types::OpaqueTypeDecl; pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog}; use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine}; @@ -12,6 +13,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::Rollback; use rustc_data_structures::unify as ut; +use rustc_data_structures::vec_map::VecMap; use rustc_errors::DiagnosticBuilder; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -25,6 +27,7 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef}; pub use rustc_middle::ty::IntVarValue; +use rustc_middle::ty::OpaqueTypeKey; use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt}; use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid}; use rustc_session::config::BorrowckMode; @@ -59,6 +62,7 @@ pub mod lattice; mod lexical_region_resolve; mod lub; pub mod nll_relate; +pub mod opaque_types; pub mod outlives; pub mod region_constraints; pub mod resolve; @@ -191,6 +195,19 @@ pub struct InferCtxtInner<'tcx> { region_obligations: Vec<(hir::HirId, RegionObligation<'tcx>)>, undo_log: InferCtxtUndoLogs<'tcx>, + + // Opaque types found in explicit return types and their + // associated fresh inference variable. Writeback resolves these + // variables to get the concrete type, which can be used to + // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions. + pub opaque_types: VecMap, OpaqueTypeDecl<'tcx>>, + + /// A map from inference variables created from opaque + /// type instantiations (`ty::Infer`) to the actual opaque + /// type (`ty::Opaque`). Used during fallback to map unconstrained + /// opaque type inference variables to their corresponding + /// opaque type. + pub opaque_types_vars: FxHashMap, Ty<'tcx>>, } impl<'tcx> InferCtxtInner<'tcx> { @@ -204,6 +221,8 @@ impl<'tcx> InferCtxtInner<'tcx> { float_unification_storage: ut::UnificationTableStorage::new(), region_constraint_storage: Some(RegionConstraintStorage::new()), region_obligations: vec![], + opaque_types: Default::default(), + opaque_types_vars: Default::default(), } } diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs new file mode 100644 index 0000000000000..4a1cbf597db35 --- /dev/null +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -0,0 +1,70 @@ +use rustc_data_structures::vec_map::VecMap; +use rustc_hir as hir; +use rustc_middle::ty::{OpaqueTypeKey, Ty}; +use rustc_span::Span; + +pub type OpaqueTypeMap<'tcx> = VecMap, OpaqueTypeDecl<'tcx>>; + +/// Information about the opaque types whose values we +/// are inferring in this function (these are the `impl Trait` that +/// appear in the return type). +#[derive(Copy, Clone, Debug)] +pub struct OpaqueTypeDecl<'tcx> { + /// The opaque type (`ty::Opaque`) for this declaration. + pub opaque_type: Ty<'tcx>, + + /// The span of this particular definition of the opaque type. So + /// for example: + /// + /// ```ignore (incomplete snippet) + /// type Foo = impl Baz; + /// fn bar() -> Foo { + /// // ^^^ This is the span we are looking for! + /// } + /// ``` + /// + /// In cases where the fn returns `(impl Trait, impl Trait)` or + /// other such combinations, the result is currently + /// over-approximated, but better than nothing. + pub definition_span: Span, + + /// The type variable that represents the value of the opaque type + /// that we require. In other words, after we compile this function, + /// we will be created a constraint like: + /// + /// Foo<'a, T> = ?C + /// + /// where `?C` is the value of this type variable. =) It may + /// naturally refer to the type and lifetime parameters in scope + /// in this function, though ultimately it should only reference + /// those that are arguments to `Foo` in the constraint above. (In + /// other words, `?C` should not include `'b`, even though it's a + /// lifetime parameter on `foo`.) + pub concrete_ty: Ty<'tcx>, + + /// Returns `true` if the `impl Trait` bounds include region bounds. + /// For example, this would be true for: + /// + /// fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b + /// + /// but false for: + /// + /// fn foo<'c>() -> impl Trait<'c> + /// + /// unless `Trait` was declared like: + /// + /// trait Trait<'c>: 'c + /// + /// in which case it would be true. + /// + /// This is used during regionck to decide whether we need to + /// impose any additional constraints to ensure that region + /// variables in `concrete_ty` wind up being constrained to + /// something from `substs` (or, at minimum, things that outlive + /// the fn body). (Ultimately, writeback is responsible for this + /// check.) + pub has_required_region_bounds: bool, + + /// The origin of the opaque type. + pub origin: hir::OpaqueTyOrigin, +} diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 95c81c5c729be..5ff1cf777f95c 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -2,11 +2,11 @@ use crate::infer::InferCtxtExt as _; use crate::traits::{self, ObligationCause, PredicateObligation}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; -use rustc_data_structures::vec_map::VecMap; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic; use rustc_infer::infer::free_regions::FreeRegionRelations; +use rustc_infer::infer::opaque_types::{OpaqueTypeDecl, OpaqueTypeMap}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{self, InferCtxt, InferOk}; use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor}; @@ -16,72 +16,6 @@ use rustc_span::Span; use std::ops::ControlFlow; -pub type OpaqueTypeMap<'tcx> = VecMap, OpaqueTypeDecl<'tcx>>; - -/// Information about the opaque types whose values we -/// are inferring in this function (these are the `impl Trait` that -/// appear in the return type). -#[derive(Copy, Clone, Debug)] -pub struct OpaqueTypeDecl<'tcx> { - /// The opaque type (`ty::Opaque`) for this declaration. - pub opaque_type: Ty<'tcx>, - - /// The span of this particular definition of the opaque type. So - /// for example: - /// - /// ```ignore (incomplete snippet) - /// type Foo = impl Baz; - /// fn bar() -> Foo { - /// // ^^^ This is the span we are looking for! - /// } - /// ``` - /// - /// In cases where the fn returns `(impl Trait, impl Trait)` or - /// other such combinations, the result is currently - /// over-approximated, but better than nothing. - pub definition_span: Span, - - /// The type variable that represents the value of the opaque type - /// that we require. In other words, after we compile this function, - /// we will be created a constraint like: - /// - /// Foo<'a, T> = ?C - /// - /// where `?C` is the value of this type variable. =) It may - /// naturally refer to the type and lifetime parameters in scope - /// in this function, though ultimately it should only reference - /// those that are arguments to `Foo` in the constraint above. (In - /// other words, `?C` should not include `'b`, even though it's a - /// lifetime parameter on `foo`.) - pub concrete_ty: Ty<'tcx>, - - /// Returns `true` if the `impl Trait` bounds include region bounds. - /// For example, this would be true for: - /// - /// fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b - /// - /// but false for: - /// - /// fn foo<'c>() -> impl Trait<'c> - /// - /// unless `Trait` was declared like: - /// - /// trait Trait<'c>: 'c - /// - /// in which case it would be true. - /// - /// This is used during regionck to decide whether we need to - /// impose any additional constraints to ensure that region - /// variables in `concrete_ty` wind up being constrained to - /// something from `substs` (or, at minimum, things that outlive - /// the fn body). (Ultimately, writeback is responsible for this - /// check.) - pub has_required_region_bounds: bool, - - /// The origin of the opaque type. - pub origin: hir::OpaqueTyOrigin, -} - /// Whether member constraints should be generated for all opaque types #[derive(Debug)] pub enum GenerateMemberConstraints { @@ -105,11 +39,7 @@ pub trait InferCtxtExt<'tcx> { value_span: Span, ) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)>; - fn constrain_opaque_types>( - &self, - opaque_types: &OpaqueTypeMap<'tcx>, - free_region_relations: &FRR, - ); + fn constrain_opaque_types>(&self, free_region_relations: &FRR); fn constrain_opaque_type>( &self, @@ -350,12 +280,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { /// - `opaque_types` -- the map produced by `instantiate_opaque_types` /// - `free_region_relations` -- something that can be used to relate /// the free regions (`'a`) that appear in the impl trait. - fn constrain_opaque_types>( - &self, - opaque_types: &OpaqueTypeMap<'tcx>, - free_region_relations: &FRR, - ) { - for &(opaque_type_key, opaque_defn) in opaque_types { + fn constrain_opaque_types>(&self, free_region_relations: &FRR) { + let opaque_types = self.inner.borrow().opaque_types.clone(); + for (opaque_type_key, opaque_defn) in opaque_types { self.constrain_opaque_type( opaque_type_key, &opaque_defn, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index f5776ae7cf66a..41642db3daab8 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -385,8 +385,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { value_span, )); - let mut opaque_types = self.opaque_types.borrow_mut(); - let mut opaque_types_vars = self.opaque_types_vars.borrow_mut(); + let mut infcx = self.infcx.inner.borrow_mut(); for (ty, decl) in opaque_type_map { if let Some(feature) = feature { @@ -402,8 +401,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - let _ = opaque_types.insert(ty, decl); - let _ = opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type); + let _ = infcx.opaque_types.insert(ty, decl); + let _ = infcx.opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type); } value @@ -726,7 +725,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We treat this as a non-defining use by making the inference // variable fall back to the opaque type itself. if let FallbackMode::All = mode { - if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) { + if let Some(opaque_ty) = self.infcx.inner.borrow().opaque_types_vars.get(ty) { debug!( "fallback_if_possible: falling back opaque type var {:?} to {:?}", ty, opaque_ty diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index 7e43e36fe55c6..fb7beae70ba1e 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -1,18 +1,15 @@ use super::callee::DeferredCallResolution; use super::MaybeInProgressTables; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::vec_map::VecMap; use rustc_hir as hir; use rustc_hir::def_id::{DefIdMap, LocalDefId}; use rustc_hir::HirIdMap; use rustc_infer::infer; use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::{self, Span}; use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::opaque_types::OpaqueTypeDecl; use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt}; use std::cell::RefCell; @@ -55,19 +52,6 @@ pub struct Inherited<'a, 'tcx> { pub(super) deferred_generator_interiors: RefCell, hir::GeneratorKind)>>, - // Opaque types found in explicit return types and their - // associated fresh inference variable. Writeback resolves these - // variables to get the concrete type, which can be used to - // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions. - pub(super) opaque_types: RefCell, OpaqueTypeDecl<'tcx>>>, - - /// A map from inference variables created from opaque - /// type instantiations (`ty::Infer`) to the actual opaque - /// type (`ty::Opaque`). Used during fallback to map unconstrained - /// opaque type inference variables to their corresponding - /// opaque type. - pub(super) opaque_types_vars: RefCell, Ty<'tcx>>>, - pub(super) body_id: Option, } @@ -124,8 +108,6 @@ impl Inherited<'a, 'tcx> { deferred_call_resolutions: RefCell::new(Default::default()), deferred_cast_checks: RefCell::new(Vec::new()), deferred_generator_interiors: RefCell::new(Vec::new()), - opaque_types: RefCell::new(Default::default()), - opaque_types_vars: RefCell::new(Default::default()), body_id, } } diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index 8f8514cadb745..ca6828cfdf68d 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -291,10 +291,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { self.visit_body(body); self.visit_region_obligations(body_id.hir_id); - self.constrain_opaque_types( - &self.fcx.opaque_types.borrow(), - self.outlives_environment.free_region_map(), - ); + self.constrain_opaque_types(self.outlives_environment.free_region_map()); } fn visit_region_obligations(&mut self, hir_id: hir::HirId) { diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index e6eac16667d4e..959ab69a679eb 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -498,7 +498,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } fn visit_opaque_types(&mut self, span: Span) { - for &(opaque_type_key, opaque_defn) in self.fcx.opaque_types.borrow().iter() { + let opaque_types = self.fcx.infcx.inner.borrow().opaque_types.clone(); + for (opaque_type_key, opaque_defn) in opaque_types { let hir_id = self.tcx().hir().local_def_id_to_hir_id(opaque_type_key.def_id.expect_local()); let instantiated_ty = self.resolve(opaque_defn.concrete_ty, &hir_id); From 14021feea92f1bb7a71338ba96bfe81ab6b9604d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 26 Jul 2021 17:09:05 +0000 Subject: [PATCH 02/13] Remove a field that is computed later anyway --- .../rustc_infer/src/infer/opaque_types.rs | 23 -------- .../rustc_trait_selection/src/opaque_types.rs | 52 +++++++++++-------- 2 files changed, 30 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 4a1cbf597db35..d0883f23a4e6b 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -42,29 +42,6 @@ pub struct OpaqueTypeDecl<'tcx> { /// lifetime parameter on `foo`.) pub concrete_ty: Ty<'tcx>, - /// Returns `true` if the `impl Trait` bounds include region bounds. - /// For example, this would be true for: - /// - /// fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b - /// - /// but false for: - /// - /// fn foo<'c>() -> impl Trait<'c> - /// - /// unless `Trait` was declared like: - /// - /// trait Trait<'c>: 'c - /// - /// in which case it would be true. - /// - /// This is used during regionck to decide whether we need to - /// impose any additional constraints to ensure that region - /// variables in `concrete_ty` wind up being constrained to - /// something from `substs` (or, at minimum, things that outlive - /// the fn body). (Ultimately, writeback is responsible for this - /// check.) - pub has_required_region_bounds: bool, - /// The origin of the opaque type. pub origin: hir::OpaqueTyOrigin, } diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 5ff1cf777f95c..4268fa0358439 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -330,19 +330,36 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let span = tcx.def_span(def_id); - // If there are required region bounds, we can use them. - if opaque_defn.has_required_region_bounds { - let bounds = tcx.explicit_item_bounds(def_id); - debug!("{:#?}", bounds); - let bounds: Vec<_> = - bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_type_key.substs)).collect(); - debug!("{:#?}", bounds); - let opaque_type = tcx.mk_opaque(def_id, opaque_type_key.substs); - - let required_region_bounds = - required_region_bounds(tcx, opaque_type, bounds.into_iter()); - debug_assert!(!required_region_bounds.is_empty()); + // Check if the `impl Trait` bounds include region bounds. + // For example, this would be true for: + // + // fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b + // + // but false for: + // + // fn foo<'c>() -> impl Trait<'c> + // + // unless `Trait` was declared like: + // + // trait Trait<'c>: 'c + // + // in which case it would be true. + // + // This is used during regionck to decide whether we need to + // impose any additional constraints to ensure that region + // variables in `concrete_ty` wind up being constrained to + // something from `substs` (or, at minimum, things that outlive + // the fn body). (Ultimately, writeback is responsible for this + // check.) + let bounds = tcx.explicit_item_bounds(def_id); + debug!("{:#?}", bounds); + let bounds: Vec<_> = + bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_type_key.substs)).collect(); + debug!("{:#?}", bounds); + let opaque_type = tcx.mk_opaque(def_id, opaque_type_key.substs); + let required_region_bounds = required_region_bounds(tcx, opaque_type, bounds.into_iter()); + if !required_region_bounds.is_empty() { for required_region in required_region_bounds { concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { op: |r| self.sub_regions(infer::CallReturn(span), required_region, r), @@ -979,9 +996,6 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { debug!("instantiate_opaque_types: bounds={:?}", bounds); - let required_region_bounds = required_region_bounds(tcx, ty, bounds.iter().copied()); - debug!("instantiate_opaque_types: required_region_bounds={:?}", required_region_bounds); - // Make sure that we are in fact defining the *entire* type // (e.g., `type Foo = impl Bar;` needs to be // defined by a function like `fn foo() -> Foo`). @@ -997,13 +1011,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { self.opaque_types.insert( OpaqueTypeKey { def_id, substs }, - OpaqueTypeDecl { - opaque_type: ty, - definition_span, - concrete_ty: ty_var, - has_required_region_bounds: !required_region_bounds.is_empty(), - origin, - }, + OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin }, ); debug!("instantiate_opaque_types: ty_var={:?}", ty_var); From 34182804e866a9f2f0c937aad5e01f8f2b7c0fda Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 26 Jul 2021 17:12:25 +0000 Subject: [PATCH 03/13] Move some code around in preparation of splitting a function --- .../rustc_trait_selection/src/opaque_types.rs | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 4268fa0358439..f74b9070535c0 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -981,21 +981,6 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { let ty_var = infcx .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }); - let item_bounds = tcx.explicit_item_bounds(def_id); - debug!("instantiate_opaque_types: bounds={:#?}", item_bounds); - let bounds: Vec<_> = - item_bounds.iter().map(|(bound, _)| bound.subst(tcx, substs)).collect(); - - let param_env = tcx.param_env(def_id); - let InferOk { value: bounds, obligations } = infcx.partially_normalize_associated_types_in( - ObligationCause::misc(span, self.body_id), - param_env, - bounds, - ); - self.obligations.extend(obligations); - - debug!("instantiate_opaque_types: bounds={:?}", bounds); - // Make sure that we are in fact defining the *entire* type // (e.g., `type Foo = impl Bar;` needs to be // defined by a function like `fn foo() -> Foo`). @@ -1015,6 +1000,21 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { ); debug!("instantiate_opaque_types: ty_var={:?}", ty_var); + let item_bounds = tcx.explicit_item_bounds(def_id); + debug!("instantiate_opaque_types: bounds={:#?}", item_bounds); + let bounds: Vec<_> = + item_bounds.iter().map(|(bound, _)| bound.subst(tcx, substs)).collect(); + + let param_env = tcx.param_env(def_id); + let InferOk { value: bounds, obligations } = infcx.partially_normalize_associated_types_in( + ObligationCause::misc(span, self.body_id), + param_env, + bounds, + ); + self.obligations.extend(obligations); + + debug!("instantiate_opaque_types: bounds={:?}", bounds); + for predicate in &bounds { if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() { if projection.ty.references_error() { From a30b548919715737817d8b66ee7867503188bbca Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 27 Jul 2021 11:46:31 +0000 Subject: [PATCH 04/13] Split fold_opaque_ty --- .../rustc_trait_selection/src/opaque_types.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index f74b9070535c0..8f23cc9e133f2 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -999,6 +999,19 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin }, ); debug!("instantiate_opaque_types: ty_var={:?}", ty_var); + self.compute_opaque_type_obligations(opaque_type_key, span); + + ty_var + } + + fn compute_opaque_type_obligations( + &mut self, + opaque_type_key: OpaqueTypeKey<'tcx>, + span: Span, + ) { + let infcx = self.infcx; + let tcx = infcx.tcx; + let OpaqueTypeKey { def_id, substs } = opaque_type_key; let item_bounds = tcx.explicit_item_bounds(def_id); debug!("instantiate_opaque_types: bounds={:#?}", item_bounds); @@ -1019,7 +1032,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() { if projection.ty.references_error() { // No point on adding these obligations since there's a type error involved. - return ty_var; + return; } } } @@ -1037,8 +1050,6 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { debug!("instantiate_opaque_types: predicate={:?}", predicate); self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate)); } - - ty_var } } From c091b5c84caccab856f0b604b4dbc88c319fe92f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 28 Jul 2021 15:43:57 +0000 Subject: [PATCH 05/13] Remove a useless feature gateing With the planned lazy TAIT system, this will not really make sense anymore anyway. --- compiler/rustc_typeck/src/check/check.rs | 65 +------------------ .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 17 +---- .../ui/type-alias-impl-trait/issue-60371.rs | 1 - .../type-alias-impl-trait/issue-60371.stderr | 11 +--- ...sue-65679-inst-opaque-ty-from-val-twice.rs | 3 +- ...65679-inst-opaque-ty-from-val-twice.stderr | 8 --- 6 files changed, 5 insertions(+), 100 deletions(-) delete mode 100644 src/test/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.stderr diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index ba99e0c03d8e2..558dd5691bbc1 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -94,69 +94,8 @@ pub(super) fn check_fn<'a, 'tcx>( let declared_ret_ty = fn_sig.output(); - let feature = match tcx.hir().get(fn_id) { - // TAIT usage in function return position. - // Example: - // - // ```rust - // type Foo = impl Debug; - // fn bar() -> Foo { 42 } - // ``` - Node::Item(hir::Item { kind: ItemKind::Fn(..), .. }) | - // TAIT usage in associated function return position. - // - // Example with a free type alias: - // - // ```rust - // type Foo = impl Debug; - // impl SomeTrait for SomeType { - // fn bar() -> Foo { 42 } - // } - // ``` - // - // Example with an associated TAIT: - // - // ```rust - // impl SomeTrait for SomeType { - // type Foo = impl Debug; - // fn bar() -> Self::Foo { 42 } - // } - // ``` - Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Fn(..), .. - }) => None, - // Forbid TAIT in trait declarations for now. - // Examples: - // - // ```rust - // type Foo = impl Debug; - // trait Bar { - // fn bar() -> Foo; - // } - // trait Bop { - // type Bop: PartialEq; - // } - // ``` - Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(..), - .. - }) | - // Forbid TAIT in closure return position for now. - // Example: - // - // ```rust - // type Foo = impl Debug; - // let x = |y| -> Foo { 42 + y }; - // ``` - Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => Some(sym::type_alias_impl_trait), - node => bug!("Item being checked wasn't a function/closure: {:?}", node), - }; - let revealed_ret_ty = fcx.instantiate_opaque_types_from_value( - fn_id, - declared_ret_ty, - decl.output.span(), - feature, - ); + let revealed_ret_ty = + fcx.instantiate_opaque_types_from_value(fn_id, declared_ret_ty, decl.output.span()); debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty); fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty))); fcx.ret_type_span = Some(decl.output.span()); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 41642db3daab8..b59ddc43c37cc 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -29,12 +29,11 @@ use rustc_middle::ty::{ }; use rustc_session::lint; use rustc_session::lint::builtin::BARE_TRAIT_OBJECTS; -use rustc_session::parse::feature_err; use rustc_span::edition::Edition; +use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::{original_sp, DUMMY_SP}; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{self, BytePos, MultiSpan, Span}; -use rustc_span::{hygiene::DesugaringKind, Symbol}; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::opaque_types::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; @@ -368,7 +367,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { parent_id: hir::HirId, value: T, value_span: Span, - feature: Option, ) -> T { let parent_def_id = self.tcx.hir().local_def_id(parent_id); debug!( @@ -388,19 +386,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut infcx = self.infcx.inner.borrow_mut(); for (ty, decl) in opaque_type_map { - if let Some(feature) = feature { - if let hir::OpaqueTyOrigin::TyAlias = decl.origin { - if !self.tcx.features().enabled(feature) { - feature_err( - &self.tcx.sess.parse_sess, - feature, - value_span, - "type alias impl trait is not permitted here", - ) - .emit(); - } - } - } let _ = infcx.opaque_types.insert(ty, decl); let _ = infcx.opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type); } diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.rs b/src/test/ui/type-alias-impl-trait/issue-60371.rs index cee5e5a01cc2a..29301767d3d69 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60371.rs +++ b/src/test/ui/type-alias-impl-trait/issue-60371.rs @@ -11,7 +11,6 @@ impl Bug for &() { //~^ ERROR the trait bound `(): Bug` is not satisfied const FUN: fn() -> Self::Item = || (); - //~^ ERROR type alias impl trait is not permitted here } fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.stderr b/src/test/ui/type-alias-impl-trait/issue-60371.stderr index 9abdd70bbd927..1e29ccd24b9a6 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60371.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-60371.stderr @@ -7,15 +7,6 @@ LL | type Item = impl Bug; = note: see issue #63063 for more information = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable -error[E0658]: type alias impl trait is not permitted here - --> $DIR/issue-60371.rs:13:40 - | -LL | const FUN: fn() -> Self::Item = || (); - | ^ - | - = note: see issue #63063 for more information - = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable - error[E0277]: the trait bound `(): Bug` is not satisfied --> $DIR/issue-60371.rs:10:17 | @@ -25,7 +16,7 @@ LL | type Item = impl Bug; = help: the following implementations were found: <&() as Bug> -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0277, E0658. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs b/src/test/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs index 0f0cd4e9227b4..72c22827f624b 100644 --- a/src/test/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs +++ b/src/test/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs @@ -1,4 +1,5 @@ // compile-flags: -Zsave-analysis +// check-pass #![feature(type_alias_impl_trait, rustc_attrs)] @@ -11,9 +12,7 @@ type T = impl Sized; fn take(_: fn() -> T) {} -#[rustc_error] fn main() { - //~^ ERROR fatal error triggered by #[rustc_error] take(|| {}); take(|| {}); } diff --git a/src/test/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.stderr b/src/test/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.stderr deleted file mode 100644 index f3683f2bf9607..0000000000000 --- a/src/test/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: fatal error triggered by #[rustc_error] - --> $DIR/issue-65679-inst-opaque-ty-from-val-twice.rs:15:1 - | -LL | fn main() { - | ^^^^^^^^^ - -error: aborting due to previous error - From 816b9fc2d1d002824908c37ed043125c3031128d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 28 Jul 2021 16:36:06 +0000 Subject: [PATCH 06/13] Remove Option only used as its Some variant --- .../src/borrow_check/type_check/mod.rs | 41 ++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index 3fb06cd2f5f44..44e38a018a6e9 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -1344,10 +1344,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { debug!("eq_opaque_type_and_type: equated"); - Ok(InferOk { - value: Some(opaque_type_map), - obligations: obligations.into_vec(), - }) + Ok(InferOk { value: opaque_type_map, obligations: obligations.into_vec() }) }, || "input_output".to_string(), ), @@ -1361,25 +1358,23 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // have to solve any bounds (e.g., `-> impl Iterator` needs to // prove that `T: Iterator` where `T` is the type we // instantiated it with). - if let Some(opaque_type_map) = opaque_type_map { - for (opaque_type_key, opaque_decl) in opaque_type_map { - self.fully_perform_op( - locations, - ConstraintCategory::OpaqueType, - CustomTypeOp::new( - |infcx| { - infcx.constrain_opaque_type( - opaque_type_key, - &opaque_decl, - GenerateMemberConstraints::IfNoStaticBound, - universal_region_relations, - ); - Ok(InferOk { value: (), obligations: vec![] }) - }, - || "opaque_type_map".to_string(), - ), - )?; - } + for (opaque_type_key, opaque_decl) in opaque_type_map { + self.fully_perform_op( + locations, + ConstraintCategory::OpaqueType, + CustomTypeOp::new( + |infcx| { + infcx.constrain_opaque_type( + opaque_type_key, + &opaque_decl, + GenerateMemberConstraints::IfNoStaticBound, + universal_region_relations, + ); + Ok(InferOk { value: (), obligations: vec![] }) + }, + || "opaque_type_map".to_string(), + ), + )?; } Ok(()) } From 20371b94f62daa33c876adafeea266f9e8b8f222 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 28 Jul 2021 18:59:25 +0000 Subject: [PATCH 07/13] Immediately register new opaque types in the global list. Previously each opaque type instantiation would create new inference vars, even for the same opaque type/substs combination. Now there is a global map in InferCtxt that gets filled whenever we encounter an opaque type. --- .../src/borrow_check/type_check/mod.rs | 126 ++++++++---------- .../rustc_trait_selection/src/opaque_types.rs | 25 ++-- compiler/rustc_typeck/src/check/_match.rs | 9 +- compiler/rustc_typeck/src/check/check.rs | 3 +- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 24 +--- .../ui/type-alias-impl-trait/issue-63279.rs | 4 +- .../type-alias-impl-trait/issue-63279.stderr | 17 ++- .../ui/type-alias-impl-trait/issue-74280.rs | 3 +- .../type-alias-impl-trait/issue-74280.stderr | 15 +-- 9 files changed, 107 insertions(+), 119 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index 44e38a018a6e9..d4edd8da7cc41 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -179,54 +179,55 @@ pub(crate) fn type_check<'mir, 'tcx>( liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table); translate_outlives_facts(&mut cx); - let mut opaque_type_values = cx.opaque_type_values; - - for (_, revealed_ty) in &mut opaque_type_values { - *revealed_ty = infcx.resolve_vars_if_possible(*revealed_ty); - if revealed_ty.has_infer_types_or_consts() { - infcx.tcx.sess.delay_span_bug( - body.span, - &format!("could not resolve {:#?}", revealed_ty.kind()), - ); - *revealed_ty = infcx.tcx.ty_error(); - } - } + let opaque_type_values = mem::take(&mut infcx.inner.borrow_mut().opaque_types); - opaque_type_values.retain(|(opaque_type_key, resolved_ty)| { - let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() { - *def_id == opaque_type_key.def_id - } else { - false - }; - - if concrete_is_opaque { - // We're using an opaque `impl Trait` type without - // 'revealing' it. For example, code like this: - // - // type Foo = impl Debug; - // fn foo1() -> Foo { ... } - // fn foo2() -> Foo { foo1() } - // - // In `foo2`, we're not revealing the type of `Foo` - we're - // just treating it as the opaque type. - // - // When this occurs, we do *not* want to try to equate - // the concrete type with the underlying defining type - // of the opaque type - this will always fail, since - // the defining type of an opaque type is always - // some other type (e.g. not itself) - // Essentially, none of the normal obligations apply here - - // we're just passing around some unknown opaque type, - // without actually looking at the underlying type it - // gets 'revealed' into - debug!( - "eq_opaque_type_and_type: non-defining use of {:?}", - opaque_type_key.def_id, - ); - } - !concrete_is_opaque - }); opaque_type_values + .into_iter() + .filter_map(|(opaque_type_key, decl)| { + let mut revealed_ty = infcx.resolve_vars_if_possible(decl.concrete_ty); + if revealed_ty.has_infer_types_or_consts() { + infcx.tcx.sess.delay_span_bug( + body.span, + &format!("could not resolve {:#?}", revealed_ty.kind()), + ); + revealed_ty = infcx.tcx.ty_error(); + } + let concrete_is_opaque = if let ty::Opaque(def_id, _) = revealed_ty.kind() { + *def_id == opaque_type_key.def_id + } else { + false + }; + + if concrete_is_opaque { + // We're using an opaque `impl Trait` type without + // 'revealing' it. For example, code like this: + // + // type Foo = impl Debug; + // fn foo1() -> Foo { ... } + // fn foo2() -> Foo { foo1() } + // + // In `foo2`, we're not revealing the type of `Foo` - we're + // just treating it as the opaque type. + // + // When this occurs, we do *not* want to try to equate + // the concrete type with the underlying defining type + // of the opaque type - this will always fail, since + // the defining type of an opaque type is always + // some other type (e.g. not itself) + // Essentially, none of the normal obligations apply here - + // we're just passing around some unknown opaque type, + // without actually looking at the underlying type it + // gets 'revealed' into + debug!( + "eq_opaque_type_and_type: non-defining use of {:?}", + opaque_type_key.def_id, + ); + None + } else { + Some((opaque_type_key, revealed_ty)) + } + }) + .collect() }, ); @@ -865,7 +866,6 @@ struct TypeChecker<'a, 'tcx> { reported_errors: FxHashSet<(Ty<'tcx>, Span)>, borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, universal_region_relations: &'a UniversalRegionRelations<'tcx>, - opaque_type_values: VecMap, Ty<'tcx>>, } struct BorrowCheckContext<'a, 'tcx> { @@ -1025,7 +1025,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { borrowck_context, reported_errors: Default::default(), universal_region_relations, - opaque_type_values: VecMap::default(), }; checker.check_user_type_annotations(); checker @@ -1289,10 +1288,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let body = self.body; let mir_def_id = body.source.def_id().expect_local(); - let mut opaque_type_values = VecMap::new(); - debug!("eq_opaque_type_and_type: mir_def_id={:?}", mir_def_id); - let opaque_type_map = self.fully_perform_op( + self.fully_perform_op( locations, category, CustomTypeOp::new( @@ -1307,20 +1304,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // to `Box`, returning an `opaque_type_map` mapping `{Foo -> ?T}`. // (Note that the key of the map is both the def-id of `Foo` along with // any generic parameters.) - let (output_ty, opaque_type_map) = - obligations.add(infcx.instantiate_opaque_types( - mir_def_id, - dummy_body_id, - param_env, - anon_ty, - locations.span(body), - )); + let output_ty = obligations.add(infcx.instantiate_opaque_types( + mir_def_id, + dummy_body_id, + param_env, + anon_ty, + locations.span(body), + )); debug!( "eq_opaque_type_and_type: \ instantiated output_ty={:?} \ - opaque_type_map={:#?} \ revealed_ty={:?}", - output_ty, opaque_type_map, revealed_ty + output_ty, revealed_ty ); // Make sure that the inferred types are well-formed. I'm @@ -1338,26 +1333,21 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .eq(output_ty, revealed_ty)?, ); - for &(opaque_type_key, opaque_decl) in &opaque_type_map { - opaque_type_values.insert(opaque_type_key, opaque_decl.concrete_ty); - } - debug!("eq_opaque_type_and_type: equated"); - Ok(InferOk { value: opaque_type_map, obligations: obligations.into_vec() }) + Ok(InferOk { value: (), obligations: obligations.into_vec() }) }, || "input_output".to_string(), ), )?; - self.opaque_type_values.extend(opaque_type_values); - let universal_region_relations = self.universal_region_relations; // Finally, if we instantiated the anon types successfully, we // have to solve any bounds (e.g., `-> impl Iterator` needs to // prove that `T: Iterator` where `T` is the type we // instantiated it with). + let opaque_type_map = self.infcx.inner.borrow().opaque_types.clone(); for (opaque_type_key, opaque_decl) in opaque_type_map { self.fully_perform_op( locations, diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 8f23cc9e133f2..70360f176bf6b 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -6,7 +6,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic; use rustc_infer::infer::free_regions::FreeRegionRelations; -use rustc_infer::infer::opaque_types::{OpaqueTypeDecl, OpaqueTypeMap}; +use rustc_infer::infer::opaque_types::OpaqueTypeDecl; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{self, InferCtxt, InferOk}; use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor}; @@ -37,7 +37,7 @@ pub trait InferCtxtExt<'tcx> { param_env: ty::ParamEnv<'tcx>, value: T, value_span: Span, - ) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)>; + ) -> InferOk<'tcx, T>; fn constrain_opaque_types>(&self, free_region_relations: &FRR); @@ -99,7 +99,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, value: T, value_span: Span, - ) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)> { + ) -> InferOk<'tcx, T> { debug!( "instantiate_opaque_types(value={:?}, parent_def_id={:?}, body_id={:?}, \ param_env={:?}, value_span={:?})", @@ -111,11 +111,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { body_id, param_env, value_span, - opaque_types: Default::default(), obligations: vec![], }; let value = instantiator.instantiate_opaque_types_in_map(value); - InferOk { value: (value, instantiator.opaque_types), obligations: instantiator.obligations } + InferOk { value, obligations: instantiator.obligations } } /// Given the map `opaque_types` containing the opaque @@ -862,7 +861,6 @@ struct Instantiator<'a, 'tcx> { body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, value_span: Span, - opaque_types: OpaqueTypeMap<'tcx>, obligations: Vec>, } @@ -972,7 +970,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { // Use the same type variable if the exact same opaque type appears more // than once in the return type (e.g., if it's passed to a type alias). - if let Some(opaque_defn) = self.opaque_types.get(&opaque_type_key) { + if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) { debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty); return opaque_defn.concrete_ty; } @@ -994,10 +992,15 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { // Foo, impl Bar)`. let definition_span = self.value_span; - self.opaque_types.insert( - OpaqueTypeKey { def_id, substs }, - OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin }, - ); + { + let mut infcx = self.infcx.inner.borrow_mut(); + infcx.opaque_types.insert( + OpaqueTypeKey { def_id, substs }, + OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin }, + ); + infcx.opaque_types_vars.insert(ty_var, ty); + } + debug!("instantiate_opaque_types: ty_var={:?}", ty_var); self.compute_opaque_type_obligations(opaque_type_key, span); diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index dee81510b795b..db88174551679 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -598,8 +598,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let impl_trait_ret_ty = self.infcx.instantiate_opaque_types(id, self.body_id, self.param_env, ty, span); - let mut suggest_box = !impl_trait_ret_ty.obligations.is_empty(); - for o in impl_trait_ret_ty.obligations { + assert!( + impl_trait_ret_ty.obligations.is_empty(), + "we should never get new obligations here" + ); + let obligations = self.fulfillment_cx.borrow().pending_obligations(); + let mut suggest_box = !obligations.is_empty(); + for o in obligations { match o.predicate.kind().skip_binder() { ty::PredicateKind::Trait(t, constness) => { let pred = ty::PredicateKind::Trait( diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 558dd5691bbc1..2496747c0619d 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -650,10 +650,11 @@ fn check_opaque_meets_bounds<'tcx>( let misc_cause = traits::ObligationCause::misc(span, hir_id); - let (_, opaque_type_map) = inh.register_infer_ok_obligations( + let _ = inh.register_infer_ok_obligations( infcx.instantiate_opaque_types(def_id, hir_id, param_env, opaque_ty, span), ); + let opaque_type_map = infcx.inner.borrow().opaque_types.clone(); for (OpaqueTypeKey { def_id, substs }, opaque_defn) in opaque_type_map { match infcx .at(&misc_cause, param_env) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index b59ddc43c37cc..ba235c142692d 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -374,23 +374,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { parent_def_id, value ); - let (value, opaque_type_map) = - self.register_infer_ok_obligations(self.instantiate_opaque_types( - parent_def_id, - self.body_id, - self.param_env, - value, - value_span, - )); - - let mut infcx = self.infcx.inner.borrow_mut(); - - for (ty, decl) in opaque_type_map { - let _ = infcx.opaque_types.insert(ty, decl); - let _ = infcx.opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type); - } - - value + self.register_infer_ok_obligations(self.instantiate_opaque_types( + parent_def_id, + self.body_id, + self.param_env, + value, + value_span, + )) } /// Convenience method which tracks extra diagnostic information for normalization diff --git a/src/test/ui/type-alias-impl-trait/issue-63279.rs b/src/test/ui/type-alias-impl-trait/issue-63279.rs index b97192a2aed4a..875cce4df2390 100644 --- a/src/test/ui/type-alias-impl-trait/issue-63279.rs +++ b/src/test/ui/type-alias-impl-trait/issue-63279.rs @@ -2,10 +2,10 @@ #![feature(type_alias_impl_trait)] -type Closure = impl FnOnce(); //~ ERROR: type mismatch resolving +type Closure = impl FnOnce(); fn c() -> Closure { - || -> Closure { || () } + || -> Closure { || () } //~ ERROR: mismatched types } fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-63279.stderr b/src/test/ui/type-alias-impl-trait/issue-63279.stderr index 63a83a60ff876..5fde8c2ef1e11 100644 --- a/src/test/ui/type-alias-impl-trait/issue-63279.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-63279.stderr @@ -1,12 +1,17 @@ -error[E0271]: type mismatch resolving `<[closure@$DIR/issue-63279.rs:8:5: 8:28] as FnOnce<()>>::Output == ()` - --> $DIR/issue-63279.rs:5:16 +error[E0308]: mismatched types + --> $DIR/issue-63279.rs:8:5 | LL | type Closure = impl FnOnce(); - | ^^^^^^^^^^^^^ expected `()`, found opaque type + | ------------- the found opaque type +... +LL | || -> Closure { || () } + | ^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure | - = note: expected unit type `()` - found opaque type `impl FnOnce<()>` + = note: expected type `[closure@$DIR/issue-63279.rs:8:21: 8:26]` + found closure `[closure@$DIR/issue-63279.rs:8:5: 8:28]` + = note: no two closures, even if identical, have the same type + = help: consider boxing your closure and/or using it as a trait object error: aborting due to previous error -For more information about this error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/type-alias-impl-trait/issue-74280.rs b/src/test/ui/type-alias-impl-trait/issue-74280.rs index d5b90a49b0521..ad641eaa00d38 100644 --- a/src/test/ui/type-alias-impl-trait/issue-74280.rs +++ b/src/test/ui/type-alias-impl-trait/issue-74280.rs @@ -6,8 +6,7 @@ type Test = impl Copy; fn test() -> Test { let y = || -> Test { () }; - //~^ ERROR: concrete type differs from previous defining opaque type use - 7 + 7 //~ ERROR mismatched types } fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-74280.stderr b/src/test/ui/type-alias-impl-trait/issue-74280.stderr index 79c7df788f46c..f6b369dd8d518 100644 --- a/src/test/ui/type-alias-impl-trait/issue-74280.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-74280.stderr @@ -1,14 +1,9 @@ -error: concrete type differs from previous defining opaque type use - --> $DIR/issue-74280.rs:8:13 +error[E0308]: mismatched types + --> $DIR/issue-74280.rs:9:5 | -LL | let y = || -> Test { () }; - | ^^^^^^^^^^^^^^^^^ expected `i32`, got `()` - | -note: previous use here - --> $DIR/issue-74280.rs:7:1 - | -LL | fn test() -> Test { - | ^^^^^^^^^^^^^^^^^ +LL | 7 + | ^ expected `()`, found integer error: aborting due to previous error +For more information about this error, try `rustc --explain E0308`. From b2c1919a3d1f0e77a64168c079caaa9610316f02 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 29 Jul 2021 15:59:59 +0000 Subject: [PATCH 08/13] Store the `DefId` of the currently typechecked item in `InferCtxt` This allows opaque type inference to check for defining uses without having to pass down that def id via function arguments to every method that could possibly cause an opaque type to be compared with a concrete type --- compiler/rustc_infer/src/infer/mod.rs | 23 +++++++++++++++++-- compiler/rustc_mir/src/borrow_check/mod.rs | 2 +- .../src/borrow_check/type_check/mod.rs | 1 - .../rustc_trait_selection/src/opaque_types.rs | 23 ++++++------------- compiler/rustc_typeck/src/check/_match.rs | 4 ++-- compiler/rustc_typeck/src/check/check.rs | 4 ++-- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 9 +------- 7 files changed, 34 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 62bfe03427e1c..e3836f667a9e9 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -9,6 +9,7 @@ pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog}; use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine}; +use hir::def_id::CRATE_DEF_ID; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::Rollback; @@ -292,6 +293,10 @@ impl<'tcx> InferCtxtInner<'tcx> { pub struct InferCtxt<'a, 'tcx> { pub tcx: TyCtxt<'tcx>, + /// The `DefId` of the item in whose context we are performing inference or typeck. + /// It is used to check whether an opaque type use is a defining use. + pub defining_use_anchor: LocalDefId, + /// During type-checking/inference of a body, `in_progress_typeck_results` /// contains a reference to the typeck results being built up, which are /// used for reading closure kinds/signatures as they are inferred, @@ -550,6 +555,7 @@ impl<'tcx> fmt::Display for FixupError<'tcx> { pub struct InferCtxtBuilder<'tcx> { tcx: TyCtxt<'tcx>, fresh_typeck_results: Option>>, + defining_use_anchor: LocalDefId, } pub trait TyCtxtInferExt<'tcx> { @@ -558,15 +564,27 @@ pub trait TyCtxtInferExt<'tcx> { impl TyCtxtInferExt<'tcx> for TyCtxt<'tcx> { fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> { - InferCtxtBuilder { tcx: self, fresh_typeck_results: None } + InferCtxtBuilder { + tcx: self, + defining_use_anchor: CRATE_DEF_ID, + fresh_typeck_results: None, + } } } impl<'tcx> InferCtxtBuilder<'tcx> { /// Used only by `rustc_typeck` during body type-checking/inference, /// will initialize `in_progress_typeck_results` with fresh `TypeckResults`. + /// Will also change the scope for opaque type defining use checks to the given owner. pub fn with_fresh_in_progress_typeck_results(mut self, table_owner: LocalDefId) -> Self { self.fresh_typeck_results = Some(RefCell::new(ty::TypeckResults::new(table_owner))); + self.with_opaque_type_inference(table_owner) + } + + /// Whenever the `InferCtxt` should be able to handle defining uses of opaque types, + /// you need to call this function. Otherwise the opaque type will be treated opaquely. + pub fn with_opaque_type_inference(mut self, defining_use_anchor: LocalDefId) -> Self { + self.defining_use_anchor = defining_use_anchor; self } @@ -594,10 +612,11 @@ impl<'tcx> InferCtxtBuilder<'tcx> { } pub fn enter(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R { - let InferCtxtBuilder { tcx, ref fresh_typeck_results } = *self; + let InferCtxtBuilder { tcx, defining_use_anchor, ref fresh_typeck_results } = *self; let in_progress_typeck_results = fresh_typeck_results.as_ref(); f(InferCtxt { tcx, + defining_use_anchor, in_progress_typeck_results, inner: RefCell::new(InferCtxtInner::new()), lexical_region_resolutions: RefCell::new(None), diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index 36eb8a4baa830..2bfa51f27bbb6 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -105,7 +105,7 @@ fn mir_borrowck<'tcx>( let (input_body, promoted) = tcx.mir_promoted(def); debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id())); - let opt_closure_req = tcx.infer_ctxt().enter(|infcx| { + let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| { let input_body: &Body<'_> = &input_body.borrow(); let promoted: &IndexVec<_, _> = &promoted.borrow(); do_mir_borrowck(&infcx, input_body, promoted) diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index d4edd8da7cc41..f69d08a6d5942 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -1305,7 +1305,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // (Note that the key of the map is both the def-id of `Foo` along with // any generic parameters.) let output_ty = obligations.add(infcx.instantiate_opaque_types( - mir_def_id, dummy_body_id, param_env, anon_ty, diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 70360f176bf6b..c24e738a7df03 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -32,7 +32,6 @@ pub enum GenerateMemberConstraints { pub trait InferCtxtExt<'tcx> { fn instantiate_opaque_types>( &self, - parent_def_id: LocalDefId, body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, value: T, @@ -94,25 +93,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { /// - `value_span` -- the span where the value came from, used in error reporting fn instantiate_opaque_types>( &self, - parent_def_id: LocalDefId, body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, value: T, value_span: Span, ) -> InferOk<'tcx, T> { debug!( - "instantiate_opaque_types(value={:?}, parent_def_id={:?}, body_id={:?}, \ + "instantiate_opaque_types(value={:?}, body_id={:?}, \ param_env={:?}, value_span={:?})", - value, parent_def_id, body_id, param_env, value_span, + value, body_id, param_env, value_span, ); - let mut instantiator = Instantiator { - infcx: self, - parent_def_id, - body_id, - param_env, - value_span, - obligations: vec![], - }; + let mut instantiator = + Instantiator { infcx: self, body_id, param_env, value_span, obligations: vec![] }; let value = instantiator.instantiate_opaque_types_in_map(value); InferOk { value, obligations: instantiator.obligations } } @@ -857,7 +849,6 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { struct Instantiator<'a, 'tcx> { infcx: &'a InferCtxt<'a, 'tcx>, - parent_def_id: LocalDefId, body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, value_span: Span, @@ -910,7 +901,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { // ``` if let Some(def_id) = def_id.as_local() { let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let parent_def_id = self.parent_def_id; + let parent_def_id = self.infcx.defining_use_anchor; let def_scope_default = || { let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id); parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id) @@ -922,14 +913,14 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { impl_trait_fn: Some(parent), origin, .. - }) => (parent == self.parent_def_id.to_def_id(), origin), + }) => (parent == parent_def_id.to_def_id(), origin), // Named `type Foo = impl Bar;` hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: None, origin, .. }) => ( - may_define_opaque_type(tcx, self.parent_def_id, opaque_hir_id), + may_define_opaque_type(tcx, parent_def_id, opaque_hir_id), origin, ), _ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias), diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index db88174551679..10c3a97e73a5a 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -593,11 +593,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { orig_expected: Expectation<'tcx>, ) -> Option { match (orig_expected, self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty))) { - (Expectation::ExpectHasType(expected), Some((id, ty))) + (Expectation::ExpectHasType(expected), Some((_id, ty))) if self.in_tail_expr && self.can_coerce(outer_ty, expected) => { let impl_trait_ret_ty = - self.infcx.instantiate_opaque_types(id, self.body_id, self.param_env, ty, span); + self.infcx.instantiate_opaque_types(self.body_id, self.param_env, ty, span); assert!( impl_trait_ret_ty.obligations.is_empty(), "we should never get new obligations here" diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 2496747c0619d..8b5b7e3e52c80 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -95,7 +95,7 @@ pub(super) fn check_fn<'a, 'tcx>( let declared_ret_ty = fn_sig.output(); let revealed_ret_ty = - fcx.instantiate_opaque_types_from_value(fn_id, declared_ret_ty, decl.output.span()); + fcx.instantiate_opaque_types_from_value(declared_ret_ty, decl.output.span()); debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty); fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty))); fcx.ret_type_span = Some(decl.output.span()); @@ -651,7 +651,7 @@ fn check_opaque_meets_bounds<'tcx>( let misc_cause = traits::ObligationCause::misc(span, hir_id); let _ = inh.register_infer_ok_obligations( - infcx.instantiate_opaque_types(def_id, hir_id, param_env, opaque_ty, span), + infcx.instantiate_opaque_types(hir_id, param_env, opaque_ty, span), ); let opaque_type_map = infcx.inner.borrow().opaque_types.clone(); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index ba235c142692d..b84a79b768c9a 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -362,20 +362,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Replaces the opaque types from the given value with type variables, /// and records the `OpaqueTypeMap` for later use during writeback. See /// `InferCtxt::instantiate_opaque_types` for more details. + #[instrument(skip(self, value_span), level = "debug")] pub(in super::super) fn instantiate_opaque_types_from_value>( &self, - parent_id: hir::HirId, value: T, value_span: Span, ) -> T { - let parent_def_id = self.tcx.hir().local_def_id(parent_id); - debug!( - "instantiate_opaque_types_from_value(parent_def_id={:?}, value={:?})", - parent_def_id, value - ); - self.register_infer_ok_obligations(self.instantiate_opaque_types( - parent_def_id, self.body_id, self.param_env, value, From 092e9ccd8aaf4cb255095b63941b8a701f5d805a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 30 Jul 2021 14:51:40 +0000 Subject: [PATCH 09/13] Point to the value instead of the TAIT declaration for obligation failures --- .../rustc_trait_selection/src/opaque_types.rs | 21 ++++++++----------- .../assoc-type-eq-with-dyn-atb-fail.rs | 2 +- .../assoc-type-eq-with-dyn-atb-fail.stderr | 6 +++--- src/test/ui/impl-trait/issue-55872-1.rs | 4 ++-- src/test/ui/impl-trait/issue-55872-1.stderr | 18 +++++++++------- src/test/ui/impl-trait/issue-55872-2.rs | 2 +- src/test/ui/impl-trait/issue-55872-2.stderr | 9 ++++---- .../generic_type_does_not_live_long_enough.rs | 4 ++-- ...eric_type_does_not_live_long_enough.stderr | 9 ++++---- .../issue-57611-trait-alias.rs | 2 +- .../issue-57611-trait-alias.stderr | 6 +++--- .../ui/type-alias-impl-trait/issue-60371.rs | 2 +- .../type-alias-impl-trait/issue-60371.stderr | 6 +++--- .../multiple-def-uses-in-one-fn.rs | 2 +- .../multiple-def-uses-in-one-fn.stderr | 6 +++--- 15 files changed, 49 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index c24e738a7df03..f7ed5cd6bd1ff 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -965,10 +965,10 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty); return opaque_defn.concrete_ty; } - let span = tcx.def_span(def_id); - debug!("fold_opaque_ty {:?} {:?}", self.value_span, span); - let ty_var = infcx - .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }); + let ty_var = infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span: self.value_span, + }); // Make sure that we are in fact defining the *entire* type // (e.g., `type Foo = impl Bar;` needs to be @@ -993,16 +993,12 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { } debug!("instantiate_opaque_types: ty_var={:?}", ty_var); - self.compute_opaque_type_obligations(opaque_type_key, span); + self.compute_opaque_type_obligations(opaque_type_key); ty_var } - fn compute_opaque_type_obligations( - &mut self, - opaque_type_key: OpaqueTypeKey<'tcx>, - span: Span, - ) { + fn compute_opaque_type_obligations(&mut self, opaque_type_key: OpaqueTypeKey<'tcx>) { let infcx = self.infcx; let tcx = infcx.tcx; let OpaqueTypeKey { def_id, substs } = opaque_type_key; @@ -1014,7 +1010,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { let param_env = tcx.param_env(def_id); let InferOk { value: bounds, obligations } = infcx.partially_normalize_associated_types_in( - ObligationCause::misc(span, self.body_id), + ObligationCause::misc(self.value_span, self.body_id), param_env, bounds, ); @@ -1038,7 +1034,8 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { // This also instantiates nested instances of `impl Trait`. let predicate = self.instantiate_opaque_types_in_map(predicate); - let cause = traits::ObligationCause::new(span, self.body_id, traits::OpaqueType); + let cause = + traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType); // Require that the predicate holds for the concrete type. debug!("instantiate_opaque_types: predicate={:?}", predicate); diff --git a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs index 7950dd3e99e29..4c36289f47b85 100644 --- a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs +++ b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs @@ -28,9 +28,9 @@ impl Bar for AssocNoCopy { impl Thing for AssocNoCopy { type Out = Box>; - //~^ ERROR the trait bound `String: Copy` is not satisfied fn func() -> Self::Out { + //~^ ERROR the trait bound `String: Copy` is not satisfied Box::new(AssocNoCopy) } } diff --git a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr index 0f1d35be0eb7a..a32ab453152a0 100644 --- a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr +++ b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `String: Copy` is not satisfied - --> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:30:28 + --> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:32:18 | -LL | type Out = Box>; - | ^^^^^^^^^^^ the trait `Copy` is not implemented for `String` +LL | fn func() -> Self::Out { + | ^^^^^^^^^ the trait `Copy` is not implemented for `String` error: aborting due to previous error diff --git a/src/test/ui/impl-trait/issue-55872-1.rs b/src/test/ui/impl-trait/issue-55872-1.rs index 72a060abae3e7..46188636475db 100644 --- a/src/test/ui/impl-trait/issue-55872-1.rs +++ b/src/test/ui/impl-trait/issue-55872-1.rs @@ -8,12 +8,12 @@ pub trait Bar { impl Bar for S { type E = impl Copy; - //~^ ERROR the trait bound `S: Copy` is not satisfied in `(S, T)` [E0277] - //~^^ ERROR the trait bound `T: Copy` is not satisfied in `(S, T)` [E0277] fn foo() -> Self::E { //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias //~| ERROR impl has stricter requirements than trait + //~| ERROR the trait bound `S: Copy` is not satisfied in `(S, T)` [E0277] + //~| ERROR the trait bound `T: Copy` is not satisfied in `(S, T)` [E0277] (S::default(), T::default()) } } diff --git a/src/test/ui/impl-trait/issue-55872-1.stderr b/src/test/ui/impl-trait/issue-55872-1.stderr index 6411c1b5d1ca2..56f5bff939fb7 100644 --- a/src/test/ui/impl-trait/issue-55872-1.stderr +++ b/src/test/ui/impl-trait/issue-55872-1.stderr @@ -1,5 +1,5 @@ error[E0276]: impl has stricter requirements than trait - --> $DIR/issue-55872-1.rs:14:5 + --> $DIR/issue-55872-1.rs:12:5 | LL | fn foo() -> Self::E; | ----------------------- definition of `foo` from trait @@ -8,10 +8,10 @@ LL | fn foo() -> Self::E { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Default` error[E0277]: the trait bound `S: Copy` is not satisfied in `(S, T)` - --> $DIR/issue-55872-1.rs:10:14 + --> $DIR/issue-55872-1.rs:12:29 | -LL | type E = impl Copy; - | ^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S` +LL | fn foo() -> Self::E { + | ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S` | = note: required because it appears within the type `(S, T)` help: consider further restricting this bound @@ -20,10 +20,10 @@ LL | impl Bar for S { | ^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `T: Copy` is not satisfied in `(S, T)` - --> $DIR/issue-55872-1.rs:10:14 + --> $DIR/issue-55872-1.rs:12:29 | -LL | type E = impl Copy; - | ^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T` +LL | fn foo() -> Self::E { + | ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T` | = note: required because it appears within the type `(S, T)` help: consider further restricting this bound @@ -32,12 +32,14 @@ LL | fn foo() -> Self::E { | ^^^^^^^^^^^^^^^^^^^ error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/issue-55872-1.rs:14:37 + --> $DIR/issue-55872-1.rs:12:37 | LL | fn foo() -> Self::E { | _____________________________________^ LL | | LL | | +LL | | +LL | | LL | | (S::default(), T::default()) LL | | } | |_____^ diff --git a/src/test/ui/impl-trait/issue-55872-2.rs b/src/test/ui/impl-trait/issue-55872-2.rs index 6eda1dc62ec62..9546d01ac5c68 100644 --- a/src/test/ui/impl-trait/issue-55872-2.rs +++ b/src/test/ui/impl-trait/issue-55872-2.rs @@ -11,9 +11,9 @@ pub trait Bar { impl Bar for S { type E = impl std::marker::Copy; - //~^ ERROR the trait bound `impl Future: Copy` is not satisfied [E0277] fn foo() -> Self::E { //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + //~| ERROR the trait bound `impl Future: Copy` is not satisfied [E0277] async {} } } diff --git a/src/test/ui/impl-trait/issue-55872-2.stderr b/src/test/ui/impl-trait/issue-55872-2.stderr index 58c5ee45051af..31b8fbd299c51 100644 --- a/src/test/ui/impl-trait/issue-55872-2.stderr +++ b/src/test/ui/impl-trait/issue-55872-2.stderr @@ -1,15 +1,16 @@ error[E0277]: the trait bound `impl Future: Copy` is not satisfied - --> $DIR/issue-55872-2.rs:13:14 + --> $DIR/issue-55872-2.rs:14:20 | -LL | type E = impl std::marker::Copy; - | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` +LL | fn foo() -> Self::E { + | ^^^^^^^ the trait `Copy` is not implemented for `impl Future` error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/issue-55872-2.rs:15:28 + --> $DIR/issue-55872-2.rs:14:28 | LL | fn foo() -> Self::E { | ____________________________^ LL | | +LL | | LL | | async {} LL | | } | |_____^ diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs index 9c6b93b7ba040..78d25e30e0382 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs @@ -7,9 +7,9 @@ fn main() { } type WrongGeneric = impl 'static; -//~^ ERROR the parameter type `T` may not live long enough -//~| ERROR: at least one trait must be specified +//~^ ERROR: at least one trait must be specified fn wrong_generic(t: T) -> WrongGeneric { + //~^ ERROR the parameter type `T` may not live long enough t } diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr index 18d8daa05e63d..568784372e519 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr @@ -19,13 +19,12 @@ LL | type WrongGeneric = impl 'static; found opaque type `impl Sized` error[E0310]: the parameter type `T` may not live long enough - --> $DIR/generic_type_does_not_live_long_enough.rs:9:24 + --> $DIR/generic_type_does_not_live_long_enough.rs:12:30 | -LL | type WrongGeneric = impl 'static; - | ^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds -... LL | fn wrong_generic(t: T) -> WrongGeneric { - | - help: consider adding an explicit lifetime bound...: `T: 'static` + | - ^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | | + | help: consider adding an explicit lifetime bound...: `T: 'static` error: aborting due to 3 previous errors diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs index a55fbf9c48a57..625e46b6bc012 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs @@ -15,9 +15,9 @@ struct X; impl Foo for X { type Bar = impl Baz; - //~^ ERROR implementation of `FnOnce` is not general enough fn bar(&self) -> Self::Bar { + //~^ ERROR implementation of `FnOnce` is not general enough |x| x } } diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr index f87beb66d995e..54d237159d80b 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr @@ -1,8 +1,8 @@ error: implementation of `FnOnce` is not general enough - --> $DIR/issue-57611-trait-alias.rs:17:16 + --> $DIR/issue-57611-trait-alias.rs:19:22 | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough +LL | fn bar(&self) -> Self::Bar { + | ^^^^^^^^^ implementation of `FnOnce` is not general enough | = note: closure with signature `fn(&'2 X) -> &X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2` diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.rs b/src/test/ui/type-alias-impl-trait/issue-60371.rs index 29301767d3d69..37a2f28ce074f 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60371.rs +++ b/src/test/ui/type-alias-impl-trait/issue-60371.rs @@ -8,9 +8,9 @@ trait Bug { impl Bug for &() { type Item = impl Bug; //~ ERROR `impl Trait` in type aliases is unstable - //~^ ERROR the trait bound `(): Bug` is not satisfied const FUN: fn() -> Self::Item = || (); + //~^ ERROR the trait bound `(): Bug` is not satisfied } fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.stderr b/src/test/ui/type-alias-impl-trait/issue-60371.stderr index 1e29ccd24b9a6..1710e07644d64 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60371.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-60371.stderr @@ -8,10 +8,10 @@ LL | type Item = impl Bug; = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0277]: the trait bound `(): Bug` is not satisfied - --> $DIR/issue-60371.rs:10:17 + --> $DIR/issue-60371.rs:12:40 | -LL | type Item = impl Bug; - | ^^^^^^^^ the trait `Bug` is not implemented for `()` +LL | const FUN: fn() -> Self::Item = || (); + | ^ the trait `Bug` is not implemented for `()` | = help: the following implementations were found: <&() as Bug> diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs index 371dff475d1d7..da845e86147b7 100644 --- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.rs @@ -5,9 +5,9 @@ #![feature(type_alias_impl_trait)] type X = impl Into<&'static A>; -//~^ ERROR the trait bound `&'static B: From<&A>` is not satisfied fn f(a: &'static A, b: B) -> (X, X) { + //~^ ERROR the trait bound `&'static B: From<&A>` is not satisfied (a, a) } diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr index 731c6e2788dde..734f15a9283de 100644 --- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `&'static B: From<&A>` is not satisfied - --> $DIR/multiple-def-uses-in-one-fn.rs:7:16 + --> $DIR/multiple-def-uses-in-one-fn.rs:9:45 | -LL | type X = impl Into<&'static A>; - | ^^^^^^^^^^^^^^^^^^^^^ the trait `From<&A>` is not implemented for `&'static B` +LL | fn f(a: &'static A, b: B) -> (X, X) { + | ^^^^^^^^^^^^^^^^^^ the trait `From<&A>` is not implemented for `&'static B` | = note: required because of the requirements on the impl of `Into<&'static B>` for `&A` help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement From 1b9ad13941b0e6959470fe6e18b06848b75c262e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 6 Aug 2021 10:11:09 +0000 Subject: [PATCH 10/13] Use existing type alias instead of manually writing it --- compiler/rustc_infer/src/infer/mod.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index e3836f667a9e9..dcd61604449ac 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -4,7 +4,7 @@ pub use self::RegionVariableOrigin::*; pub use self::SubregionOrigin::*; pub use self::ValuePairs::*; -use self::opaque_types::OpaqueTypeDecl; +use self::opaque_types::OpaqueTypeMap; pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog}; use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine}; @@ -14,7 +14,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::Rollback; use rustc_data_structures::unify as ut; -use rustc_data_structures::vec_map::VecMap; use rustc_errors::DiagnosticBuilder; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -28,7 +27,6 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef}; pub use rustc_middle::ty::IntVarValue; -use rustc_middle::ty::OpaqueTypeKey; use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt}; use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid}; use rustc_session::config::BorrowckMode; @@ -201,7 +199,7 @@ pub struct InferCtxtInner<'tcx> { // associated fresh inference variable. Writeback resolves these // variables to get the concrete type, which can be used to // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions. - pub opaque_types: VecMap, OpaqueTypeDecl<'tcx>>, + pub opaque_types: OpaqueTypeMap<'tcx>, /// A map from inference variables created from opaque /// type instantiations (`ty::Infer`) to the actual opaque From 238d974fc6fc3d28e35223c0cb4ef562e15f6728 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 6 Aug 2021 10:49:35 +0000 Subject: [PATCH 11/13] Document `with_opaque_type_inference`'s use cases. --- compiler/rustc_infer/src/infer/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index dcd61604449ac..10217a5f57498 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -581,6 +581,10 @@ impl<'tcx> InferCtxtBuilder<'tcx> { /// Whenever the `InferCtxt` should be able to handle defining uses of opaque types, /// you need to call this function. Otherwise the opaque type will be treated opaquely. + /// + /// It is only meant to be called in two places, for typeck + /// (via `with_fresh_in_progress_typeck_results`) and for the inference context used + /// in mir borrowck. pub fn with_opaque_type_inference(mut self, defining_use_anchor: LocalDefId) -> Self { self.defining_use_anchor = defining_use_anchor; self From 7af445dc15924e68d9c3a0fdd506e762aaa00b79 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 6 Aug 2021 11:06:34 +0000 Subject: [PATCH 12/13] bless some nll tests --- ..._type_does_not_live_long_enough.nll.stderr | 2 +- .../issue-57611-trait-alias.nll.stderr | 26 +------------------ 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr index 84f48cd6c0d20..f4e1de8e50f68 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr @@ -19,7 +19,7 @@ LL | type WrongGeneric = impl 'static; found opaque type `impl Sized` error[E0310]: the parameter type `T` may not live long enough - --> $DIR/generic_type_does_not_live_long_enough.rs:13:30 + --> $DIR/generic_type_does_not_live_long_enough.rs:12:30 | LL | fn wrong_generic(t: T) -> WrongGeneric { | ^^^^^^^^^^^^^^^ diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr index a4ccae4eb7ed9..8c9cb742fac91 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr @@ -10,29 +10,5 @@ error: higher-ranked subtype error LL | |x| x | ^^^^^ -error[E0308]: mismatched types - --> $DIR/issue-57611-trait-alias.rs:17:16 - | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other - | - = note: expected type `for<'r> Fn<(&'r X,)>` - found type `Fn<(&'static X,)>` -note: this closure does not fulfill the lifetime requirements - --> $DIR/issue-57611-trait-alias.rs:21:9 - | -LL | |x| x - | ^^^^^ - -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-57611-trait-alias.rs:17:16 - | -LL | type Bar = impl Baz; - | ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'static X) -> &'static X` must implement `FnOnce<(&'0 X,)>`, for any lifetime `'0`... - = note: ...but it actually implements `FnOnce<(&'static X,)>` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. From 93c4aa80b805bd2f0685e3438cb851ff8775415c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 10 Aug 2021 11:03:10 +0000 Subject: [PATCH 13/13] Don't collect into a `Vec` that is immediately being iterated on again. --- compiler/rustc_trait_selection/src/opaque_types.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index f7ed5cd6bd1ff..1a195ce18ec64 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -344,12 +344,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // check.) let bounds = tcx.explicit_item_bounds(def_id); debug!("{:#?}", bounds); - let bounds: Vec<_> = - bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_type_key.substs)).collect(); + let bounds = bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_type_key.substs)); debug!("{:#?}", bounds); let opaque_type = tcx.mk_opaque(def_id, opaque_type_key.substs); - let required_region_bounds = required_region_bounds(tcx, opaque_type, bounds.into_iter()); + let required_region_bounds = required_region_bounds(tcx, opaque_type, bounds); if !required_region_bounds.is_empty() { for required_region in required_region_bounds { concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {