From 20371b94f62daa33c876adafeea266f9e8b8f222 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 28 Jul 2021 18:59:25 +0000 Subject: [PATCH] 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 44e38a018a6..d4edd8da7cc 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 @@ fn new( borrowck_context, reported_errors: Default::default(), universal_region_relations, - opaque_type_values: VecMap::default(), }; checker.check_user_type_annotations(); checker @@ -1289,10 +1288,8 @@ fn eq_opaque_type_and_type( 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 @@ fn eq_opaque_type_and_type( // 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 @@ fn eq_opaque_type_and_type( .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 8f23cc9e133..70360f176bf 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::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 @@ fn instantiate_opaque_types>( 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 @@ fn instantiate_opaque_types>( 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 @@ fn instantiate_opaque_types>( 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 @@ fn fold_opaque_ty( // 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 @@ fn fold_opaque_ty( // 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 dee81510b79..db881745516 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -598,8 +598,13 @@ pub(crate) fn opt_suggest_box_span( { 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 558dd5691bb..2496747c061 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 b59ddc43c37..ba235c14269 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 @@ pub(in super::super) fn instantiate_opaque_types_from_value 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 63a83a60ff8..5fde8c2ef1e 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 d5b90a49b05..ad641eaa00d 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 @@ 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 79c7df788f4..f6b369dd8d5 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`. -- 2.44.0