@@ -90,7 +90,7 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
90
90
use rustc_back:: slice:: ref_slice;
91
91
use namespace:: Namespace ;
92
92
use rustc:: infer:: { self , InferCtxt , InferOk , RegionVariableOrigin } ;
93
- use rustc:: infer:: type_variable:: { TypeVariableOrigin , Default } ;
93
+ use rustc:: infer:: type_variable:: TypeVariableOrigin ;
94
94
use rustc:: middle:: region;
95
95
use rustc:: ty:: subst:: { Kind , Subst , Substs } ;
96
96
use rustc:: traits:: { self , FulfillmentContext , ObligationCause , ObligationCauseCode } ;
@@ -2185,13 +2185,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
2185
2185
/// will have `String` as its default.
2186
2186
///
2187
2187
/// Adding a default to a type parameter that has none should be backwards compatible.
2188
- /// However if we get conflicting defaults we do not know how to resolve them.
2189
- /// Therefore we must future-proof against such a conflict by not allowing
2190
- /// type variables with defaults to unify with type variables without defaults.
2188
+ /// Therefore we take care to future-proof against conflicting defaults.
2191
2189
///
2192
- /// We may come up with rules to prioritize a type parameter over another.
2193
- /// When unifying type variables, the highest priority parameter involved
2194
- /// has the final say on what the default should be.
2195
2190
/// Currently we prioritize defaults from impls and fns over defaults in types,
2196
2191
/// this for example allows `fn foo<T=String>(x: Option<T>)` to work
2197
2192
/// even though `Option<T>` has no default for `T`.
@@ -2215,10 +2210,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
2215
2210
bags. entry ( root) . or_insert ( Vec :: new ( ) ) . push ( vid) ;
2216
2211
}
2217
2212
}
2218
- // A bag will successfuly fallback to a default if all of it's variables
2219
- // have a default, and that default is the same.
2220
- // Low priority variables will be ignored in the presence of higher priority variables.
2221
- ' bags: for ( _, mut bag) in bags. into_iter ( ) {
2213
+
2214
+ // Attempt to find a fallback for each bag.
2215
+ for ( _, bag) in bags {
2222
2216
// Partition the bag by the origin of the type param.
2223
2217
let ( fn_or_impl, ty_def) = bag. into_iter ( ) . partition ( |& v| {
2224
2218
match self . infcx . type_variables . borrow ( ) . var_origin ( v) {
@@ -2228,37 +2222,53 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
2228
2222
_ => bug ! ( "type var does not support fallback" )
2229
2223
}
2230
2224
} ) ;
2231
- // Params from fns or impls take priority, if they exist ignore the rest of the bag.
2232
- bag = fn_or_impl;
2233
- if bag. is_empty ( ) {
2234
- bag = ty_def;
2235
- }
2236
- // For future-proofing against conflicting defaults,
2237
- // if one of the variables has no default, nothing is unified.
2238
- for & vid in & bag {
2239
- let default = self . infcx . type_variables . borrow ( ) . default ( vid) . clone ( ) ;
2240
- debug ! ( "apply_user_type_parameter_fallback: \
2241
- checking var: {:?} with default: {:?}", vid, default ) ;
2242
- match default {
2243
- Default :: User ( _) => { } ,
2244
- _ => continue ' bags,
2225
+ // Params from fns or impls have higher priority than those from type definitions.
2226
+ // We consider the priority levels in order and stop at the first success or failure:
2227
+ // We succeed if all defaults exist and agree.
2228
+ // We fail if existing defaults agree but there are missing defaults.
2229
+ // We continue if the priority level is empty or if there are any disagreements.
2230
+ let priority_levels: Vec < Vec < ty:: TyVid > > = vec ! [ fn_or_impl, ty_def] ;
2231
+ ' priority_levels: for priority_level in priority_levels {
2232
+ if priority_level. is_empty ( ) {
2233
+ continue ;
2245
2234
}
2246
- }
2247
- for & vid in & bag {
2248
- // If future-proof, then all vars have defaults.
2249
- let default = self . infcx . type_variables . borrow ( ) . default ( vid) . clone ( ) ;
2250
- let ty = self . tcx . mk_var ( vid) ;
2251
- debug ! ( "apply_user_type_parameter_fallback: applying fallback to var: {:?} \
2252
- with ty: {:?} with default: {:?}", vid, ty, default ) ;
2253
- if let Default :: User ( user_default) = default {
2254
- let normalized_default = self . normalize_associated_types_in (
2255
- user_default. origin_span ,
2256
- & user_default. ty ) ;
2257
- // QUESTION(leodasvacas):
2258
- // This will emit "expected type mismatch" on conflicting defaults, which is bad.
2259
- // I'd be happy to somehow detect or rollback this demand on conflict defaults
2260
- // so we would emit "type annotations needed" instead.
2261
- self . demand_eqtype ( user_default. origin_span , & ty, normalized_default) ;
2235
+ let normalized_default = |& vid| {
2236
+ let default = self . infcx . type_variables . borrow ( ) . default ( vid) . get_user ( ) ;
2237
+ default. map ( |d| self . normalize_associated_types_in ( d. origin_span , & d. ty ) )
2238
+ } ;
2239
+ let mut existing_defaults = priority_level. iter ( ) . filter_map ( & normalized_default) ;
2240
+ let equivalent_default = match existing_defaults. next ( ) {
2241
+ Some ( default) => default,
2242
+ None => break , // Failed, no params have defaults at this level.
2243
+ } ;
2244
+
2245
+ // If there are conflicting defaults, skip this level.
2246
+ // FIXME(leodasvacas): In a case like `impl<X: Default=u32, Y = <X as Id>::This>`,
2247
+ // as found in the test "dependent_associated_type.rs",
2248
+ // if `Y` is normalized before the default of `X` is applied,
2249
+ // then it's normalized to `TyInfer`, so we use a fragile workaround here.
2250
+ // If it is `Y = Vec<<X as Id>::This>` we are in trouble again.
2251
+ // Type equality that considers all inference variables equal is a correct fix.
2252
+ if existing_defaults. any ( |default| match ( & default. sty , & equivalent_default. sty ) {
2253
+ ( & ty:: TyInfer ( _) , & ty:: TyInfer ( _) ) => false ,
2254
+ ( ref a, ref b) => * * a != * * b
2255
+ } )
2256
+ {
2257
+ debug ! ( "apply_user_type_parameter_fallback: skipping priority level" ) ;
2258
+ continue ;
2259
+ }
2260
+ // All existing defaults agree, but for future-proofing
2261
+ // we must fail if there is a param with no default.
2262
+ if priority_level. iter ( ) . any ( |vid| normalized_default ( vid) == None ) {
2263
+ break ;
2264
+ }
2265
+ // All defaults exist and agree, apply the default and succeed.
2266
+ for & vid in & priority_level {
2267
+ let ty = self . tcx . mk_var ( vid) ;
2268
+ debug ! ( "apply_user_type_parameter_fallback: applying fallback to var: {:?} \
2269
+ with ty: {:?} with default: {:?}", vid, ty, equivalent_default) ;
2270
+ self . demand_eqtype ( syntax_pos:: DUMMY_SP , & ty, equivalent_default) ;
2271
+ break ' priority_levels;
2262
2272
}
2263
2273
}
2264
2274
}
0 commit comments