@@ -147,7 +147,7 @@ use crate::TypeAndSubsts;
147147use crate :: lint;
148148use crate :: util:: captures:: Captures ;
149149use crate :: util:: common:: { ErrorReported , indenter} ;
150- use crate :: util:: nodemap:: { DefIdMap , DefIdSet , FxHashSet , HirIdMap } ;
150+ use crate :: util:: nodemap:: { DefIdMap , DefIdSet , FxHashMap , FxHashSet , HirIdMap } ;
151151
152152pub use self :: Expectation :: * ;
153153use self :: autoderef:: Autoderef ;
@@ -231,6 +231,13 @@ pub struct Inherited<'a, 'tcx> {
231231 // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
232232 opaque_types : RefCell < DefIdMap < OpaqueTypeDecl < ' tcx > > > ,
233233
234+ /// A map from inference variables created from opaque
235+ /// type instantiations (ty::Infer) to the actual opaque
236+ /// type (`ty::Opaque`). Used during fallback to map unconstrained
237+ /// opaque type inference variables to their corresponding
238+ /// opaque type.
239+ opaque_types_vars : RefCell < FxHashMap < Ty < ' tcx > , Ty < ' tcx > > > ,
240+
234241 /// Each type parameter has an implicit region bound that
235242 /// indicates it must outlive at least the function body (the user
236243 /// may specify stronger requirements). This field indicates the
@@ -696,6 +703,7 @@ impl Inherited<'a, 'tcx> {
696703 deferred_cast_checks : RefCell :: new ( Vec :: new ( ) ) ,
697704 deferred_generator_interiors : RefCell :: new ( Vec :: new ( ) ) ,
698705 opaque_types : RefCell :: new ( Default :: default ( ) ) ,
706+ opaque_types_vars : RefCell :: new ( Default :: default ( ) ) ,
699707 implicit_region_bound,
700708 body_id,
701709 }
@@ -937,9 +945,46 @@ fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> {
937945 // All type checking constraints were added, try to fallback unsolved variables.
938946 fcx. select_obligations_where_possible ( false , |_| { } ) ;
939947 let mut fallback_has_occurred = false ;
948+
949+ // We do fallback in two passes, to try to generate
950+ // better error messages.
951+ // The first time, we do *not* replace opaque types.
952+ for ty in & fcx. unsolved_variables ( ) {
953+ fallback_has_occurred |= fcx. fallback_if_possible ( ty, false /* opaque_fallback */ ) ;
954+ }
955+ // We now see if we can make progress. This might
956+ // cause us to unify inference variables for opaque types,
957+ // since we may have unified some other type variables
958+ // during the first phase of fallback.
959+ // This means that we only replace inference variables with their underlying
960+ // opaque types as a last resort.
961+ //
962+ // In code like this:
963+ //
964+ // ```rust
965+ // type MyType = impl Copy;
966+ // fn produce() -> MyType { true }
967+ // fn bad_produce() -> MyType { panic!() }
968+ // ```
969+ //
970+ // we want to unify the opaque inference variable in `bad_produce`
971+ // with the diverging fallback for `panic!` (e.g. `()` or `!`),
972+ // This will produce a nice error message about conflicting concrete
973+ // types for `MyType`.
974+ //
975+ // If we had tried to fallback the opaque inference variable to `MyType`,
976+ // we will generate a confusing type-check error that does not explicitly
977+ // refer to opaque types.
978+ fcx. select_obligations_where_possible ( fallback_has_occurred, |_| { } ) ;
979+
980+ // We now run fallback again, but this time we allow it to replace
981+ // unconstrained opaque type variables, in addition to performing
982+ // other kinds of fallback.
940983 for ty in & fcx. unsolved_variables ( ) {
941- fallback_has_occurred |= fcx. fallback_if_possible ( ty) ;
984+ fallback_has_occurred |= fcx. fallback_if_possible ( ty, true /* opaque_fallback */ ) ;
942985 }
986+
987+ // See if we can make any more progress
943988 fcx. select_obligations_where_possible ( fallback_has_occurred, |_| { } ) ;
944989
945990 // Even though coercion casts provide type hints, we check casts after fallback for
@@ -2864,8 +2909,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
28642909 ) ;
28652910
28662911 let mut opaque_types = self . opaque_types . borrow_mut ( ) ;
2912+ let mut opaque_types_vars = self . opaque_types_vars . borrow_mut ( ) ;
28672913 for ( ty, decl) in opaque_type_map {
28682914 let _ = opaque_types. insert ( ty, decl) ;
2915+ let _ = opaque_types_vars. insert ( decl. concrete_ty , decl. opaque_type ) ;
28692916 }
28702917
28712918 value
@@ -3078,7 +3125,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
30783125 // Fallback becomes very dubious if we have encountered type-checking errors.
30793126 // In that case, fallback to Error.
30803127 // The return value indicates whether fallback has occurred.
3081- fn fallback_if_possible ( & self , ty : Ty < ' tcx > ) -> bool {
3128+ fn fallback_if_possible ( & self , ty : Ty < ' tcx > , opaque_fallback : bool ) -> bool {
30823129 use rustc:: ty:: error:: UnconstrainedNumeric :: Neither ;
30833130 use rustc:: ty:: error:: UnconstrainedNumeric :: { UnconstrainedInt , UnconstrainedFloat } ;
30843131
@@ -3088,7 +3135,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
30883135 UnconstrainedInt => self . tcx . types . i32 ,
30893136 UnconstrainedFloat => self . tcx . types . f64 ,
30903137 Neither if self . type_var_diverges ( ty) => self . tcx . mk_diverging_default ( ) ,
3091- Neither => return false ,
3138+ Neither => {
3139+ // This type variable was created from the instantiation of an opaque
3140+ // type. The fact that we're attempting to perform fallback for it
3141+ // means that the function neither constrained it to a concrete
3142+ // type, nor to the opaque type itself.
3143+ //
3144+ // For example, in this code:
3145+ //
3146+ //```
3147+ // type MyType = impl Copy;
3148+ // fn defining_use() -> MyType { true }
3149+ // fn other_use() -> MyType { defining_use() }
3150+ // ```
3151+ //
3152+ // `defining_use` will constrain the instantiated inference
3153+ // variable to `bool`, while `other_use` will constrain
3154+ // the instantiated inference variable to `MyType`.
3155+ //
3156+ // When we process opaque types during writeback, we
3157+ // will handle cases like `other_use`, and not count
3158+ // them as defining usages
3159+ //
3160+ // However, we also need to handle cases like this:
3161+ //
3162+ // ```rust
3163+ // pub type Foo = impl Copy;
3164+ // fn produce() -> Option<Foo> {
3165+ // None
3166+ // }
3167+ // ```
3168+ //
3169+ // In the above snippet, the inference varaible created by
3170+ // instantiating `Option<Foo>` will be completely unconstrained.
3171+ // We treat this as a non-defining use by making the inference
3172+ // variable fall back to the opaque type itself.
3173+ if opaque_fallback {
3174+ if let Some ( opaque_ty) = self . opaque_types_vars . borrow ( ) . get ( ty) {
3175+ debug ! ( "fallback_if_possible: falling back opaque type var {:?} to {:?}" ,
3176+ ty, opaque_ty) ;
3177+ * opaque_ty
3178+ } else {
3179+ return false ;
3180+ }
3181+ } else {
3182+ return false ;
3183+ }
3184+ } ,
30923185 } ;
30933186 debug ! ( "fallback_if_possible: defaulting `{:?}` to `{:?}`" , ty, fallback) ;
30943187 self . demand_eqtype ( syntax_pos:: DUMMY_SP , ty, fallback) ;
0 commit comments