@@ -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.
940952 for ty in & fcx. unsolved_variables ( ) {
941- fallback_has_occurred |= fcx. fallback_if_possible ( ty) ;
953+ fallback_has_occurred |= fcx. fallback_if_possible ( ty, FallbackMode :: NoOpaque ) ;
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.
983+ for ty in & fcx. unsolved_variables ( ) {
984+ fallback_has_occurred |= fcx. fallback_if_possible ( ty, FallbackMode :: All ) ;
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
@@ -2499,6 +2544,16 @@ enum TupleArgumentsFlag {
24992544 TupleArguments ,
25002545}
25012546
2547+ /// Controls how we perform fallback for unconstrained
2548+ /// type variables.
2549+ enum FallbackMode {
2550+ /// Do not fallback type variables to opaque types.
2551+ NoOpaque ,
2552+ /// Perform all possible kinds of fallback, including
2553+ /// turning type variables to opaque types.
2554+ All ,
2555+ }
2556+
25022557impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
25032558 pub fn new (
25042559 inh : & ' a Inherited < ' a , ' tcx > ,
@@ -2864,8 +2919,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
28642919 ) ;
28652920
28662921 let mut opaque_types = self . opaque_types . borrow_mut ( ) ;
2922+ let mut opaque_types_vars = self . opaque_types_vars . borrow_mut ( ) ;
28672923 for ( ty, decl) in opaque_type_map {
28682924 let _ = opaque_types. insert ( ty, decl) ;
2925+ let _ = opaque_types_vars. insert ( decl. concrete_ty , decl. opaque_type ) ;
28692926 }
28702927
28712928 value
@@ -3078,7 +3135,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
30783135 // Fallback becomes very dubious if we have encountered type-checking errors.
30793136 // In that case, fallback to Error.
30803137 // The return value indicates whether fallback has occurred.
3081- fn fallback_if_possible ( & self , ty : Ty < ' tcx > ) -> bool {
3138+ fn fallback_if_possible ( & self , ty : Ty < ' tcx > , mode : FallbackMode ) -> bool {
30823139 use rustc:: ty:: error:: UnconstrainedNumeric :: Neither ;
30833140 use rustc:: ty:: error:: UnconstrainedNumeric :: { UnconstrainedInt , UnconstrainedFloat } ;
30843141
@@ -3088,7 +3145,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
30883145 UnconstrainedInt => self . tcx . types . i32 ,
30893146 UnconstrainedFloat => self . tcx . types . f64 ,
30903147 Neither if self . type_var_diverges ( ty) => self . tcx . mk_diverging_default ( ) ,
3091- Neither => return false ,
3148+ Neither => {
3149+ // This type variable was created from the instantiation of an opaque
3150+ // type. The fact that we're attempting to perform fallback for it
3151+ // means that the function neither constrained it to a concrete
3152+ // type, nor to the opaque type itself.
3153+ //
3154+ // For example, in this code:
3155+ //
3156+ //```
3157+ // type MyType = impl Copy;
3158+ // fn defining_use() -> MyType { true }
3159+ // fn other_use() -> MyType { defining_use() }
3160+ // ```
3161+ //
3162+ // `defining_use` will constrain the instantiated inference
3163+ // variable to `bool`, while `other_use` will constrain
3164+ // the instantiated inference variable to `MyType`.
3165+ //
3166+ // When we process opaque types during writeback, we
3167+ // will handle cases like `other_use`, and not count
3168+ // them as defining usages
3169+ //
3170+ // However, we also need to handle cases like this:
3171+ //
3172+ // ```rust
3173+ // pub type Foo = impl Copy;
3174+ // fn produce() -> Option<Foo> {
3175+ // None
3176+ // }
3177+ // ```
3178+ //
3179+ // In the above snippet, the inference varaible created by
3180+ // instantiating `Option<Foo>` will be completely unconstrained.
3181+ // We treat this as a non-defining use by making the inference
3182+ // variable fall back to the opaque type itself.
3183+ if let FallbackMode :: All = mode {
3184+ if let Some ( opaque_ty) = self . opaque_types_vars . borrow ( ) . get ( ty) {
3185+ debug ! ( "fallback_if_possible: falling back opaque type var {:?} to {:?}" ,
3186+ ty, opaque_ty) ;
3187+ * opaque_ty
3188+ } else {
3189+ return false ;
3190+ }
3191+ } else {
3192+ return false ;
3193+ }
3194+ } ,
30923195 } ;
30933196 debug ! ( "fallback_if_possible: defaulting `{:?}` to `{:?}`" , ty, fallback) ;
30943197 self . demand_eqtype ( syntax_pos:: DUMMY_SP , ty, fallback) ;
0 commit comments