@@ -117,23 +117,71 @@ pub enum MethodMatchedData {
117
117
/// obligation is for `int`. In that case, we drop the impl out of the
118
118
/// list. But the other cases are considered *candidates*.
119
119
///
120
- /// Candidates can either be definitive or ambiguous. An ambiguous
121
- /// candidate is one that might match or might not, depending on how
122
- /// type variables wind up being resolved. This only occurs during inference.
120
+ /// For selection to succeed, there must be exactly one matching
121
+ /// candidate. If the obligation is fully known, this is guaranteed
122
+ /// by coherence. However, if the obligation contains type parameters
123
+ /// or variables, there may be multiple such impls.
123
124
///
124
- /// For selection to succeed, there must be exactly one non-ambiguous
125
- /// candidate. Usually, it is not possible to have more than one
126
- /// definitive candidate, due to the coherence rules. However, there is
127
- /// one case where it could occur: if there is a blanket impl for a
128
- /// trait (that is, an impl applied to all T), and a type parameter
129
- /// with a where clause. In that case, we can have a candidate from the
130
- /// where clause and a second candidate from the impl. This is not a
131
- /// problem because coherence guarantees us that the impl which would
132
- /// be used to satisfy the where clause is the same one that we see
133
- /// now. To resolve this issue, therefore, we ignore impls if we find a
134
- /// matching where clause. Part of the reason for this is that where
135
- /// clauses can give additional information (like, the types of output
136
- /// parameters) that would have to be inferred from the impl.
125
+ /// It is not a real problem if multiple matching impls exist because
126
+ /// of type variables - it just means the obligation isn't sufficiently
127
+ /// elaborated. In that case we report an ambiguity, and the caller can
128
+ /// try again after more type information has been gathered or report a
129
+ /// "type annotations required" error.
130
+ ///
131
+ /// However, with type parameters, this can be a real problem - type
132
+ /// parameters don't unify with regular types, but they *can* unify
133
+ /// with variables from blanket impls, and (unless we know its bounds
134
+ /// will always be satisfied) picking the blanket impl will be wrong
135
+ /// for at least *some* substitutions. To make this concrete, if we have
136
+ ///
137
+ /// trait AsDebug { type Out : fmt::Debug; fn debug(self) -> Self::Out; }
138
+ /// impl<T: fmt::Debug> AsDebug for T {
139
+ /// type Out = T;
140
+ /// fn debug(self) -> fmt::Debug { self }
141
+ /// }
142
+ /// fn foo<T: AsDebug>(t: T) { println!("{:?}", <T as AsDebug>::debug(t)); }
143
+ ///
144
+ /// we can't just use the impl to resolve the <T as AsDebug> obligation
145
+ /// - a type from another crate (that doesn't implement fmt::Debug) could
146
+ /// implement AsDebug.
147
+ ///
148
+ /// Because where-clauses match the type exactly, multiple clauses can
149
+ /// only match if there are unresolved variables, and we can mostly just
150
+ /// report this ambiguity in that case. This is still a problem - we can't
151
+ /// *do anything* with ambiguities that involve only regions. This is issue
152
+ /// #21974.
153
+ ///
154
+ /// If a single where-clause matches and there are no inference
155
+ /// variables left, then it definitely matches and we can just select
156
+ /// it.
157
+ ///
158
+ /// In fact, we even select the where-clause when the obligation contains
159
+ /// inference variables. The can lead to inference making "leaps of logic",
160
+ /// for example in this situation:
161
+ ///
162
+ /// pub trait Foo<T> { fn foo(&self) -> T; }
163
+ /// impl<T> Foo<()> for T { fn foo(&self) { } }
164
+ /// impl Foo<bool> for bool { fn foo(&self) -> bool { *self } }
165
+ ///
166
+ /// pub fn foo<T>(t: T) where T: Foo<bool> {
167
+ /// println!("{:?}", <T as Foo<_>>::foo(&t));
168
+ /// }
169
+ /// fn main() { foo(false); }
170
+ ///
171
+ /// Here the obligation <T as Foo<$0>> can be matched by both the blanket
172
+ /// impl and the where-clause. We select the where-clause and unify $0=bool,
173
+ /// so the program prints "false". However, if the where-clause is omitted,
174
+ /// the blanket impl is selected, we unify $0=(), and the program prints
175
+ /// "()".
176
+ ///
177
+ /// Exactly the same issues apply to projection and object candidates, except
178
+ /// that we can have both a projection candidate and a where-clause candidate
179
+ /// for the same obligation. In that case either would do (except that
180
+ /// different "leaps of logic" would occur if inference variables are
181
+ /// present), and we just pick the projection. This is, for example,
182
+ /// required for associated types to work in default impls, as the bounds
183
+ /// are visible both as projection bounds and as where-clauses from the
184
+ /// parameter environment.
137
185
#[ derive( PartialEq , Eq , Debug , Clone ) ]
138
186
enum SelectionCandidate < ' tcx > {
139
187
PhantomFnCandidate ,
@@ -1350,63 +1398,51 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
1350
1398
/// Returns true if `candidate_i` should be dropped in favor of
1351
1399
/// `candidate_j`. Generally speaking we will drop duplicate
1352
1400
/// candidates and prefer where-clause candidates.
1401
+ /// Returns true if `victim` should be dropped in favor of
1402
+ /// `other`. Generally speaking we will drop duplicate
1403
+ /// candidates and prefer where-clause candidates.
1404
+ ///
1405
+ /// See the comment for "SelectionCandidate" for more details.
1353
1406
fn candidate_should_be_dropped_in_favor_of < ' o > ( & mut self ,
1354
- candidate_i : & SelectionCandidate < ' tcx > ,
1355
- candidate_j : & SelectionCandidate < ' tcx > )
1407
+ victim : & SelectionCandidate < ' tcx > ,
1408
+ other : & SelectionCandidate < ' tcx > )
1356
1409
-> bool
1357
1410
{
1358
- if candidate_i == candidate_j {
1411
+ if victim == other {
1359
1412
return true ;
1360
1413
}
1361
1414
1362
- match ( candidate_i, candidate_j) {
1363
- ( & ImplCandidate ( ..) , & ParamCandidate ( ..) ) |
1364
- ( & ClosureCandidate ( ..) , & ParamCandidate ( ..) ) |
1365
- ( & FnPointerCandidate ( ..) , & ParamCandidate ( ..) ) |
1366
- ( & BuiltinObjectCandidate ( ..) , & ParamCandidate ( _) ) |
1367
- ( & BuiltinCandidate ( ..) , & ParamCandidate ( ..) ) => {
1368
- // We basically prefer always prefer to use a
1369
- // where-clause over another option. Where clauses
1370
- // impose the burden of finding the exact match onto
1371
- // the caller. Using an impl in preference of a where
1372
- // clause can also lead us to "overspecialize", as in
1373
- // #18453.
1374
- true
1375
- }
1376
- ( & ImplCandidate ( ..) , & ObjectCandidate ( ..) ) => {
1377
- // This means that we are matching an object of type
1378
- // `Trait` against the trait `Trait`. In that case, we
1379
- // always prefer to use the object vtable over the
1380
- // impl. Like a where clause, the impl may or may not
1381
- // be the one that is used by the object (because the
1382
- // impl may have additional where-clauses that the
1383
- // object's source might not meet) -- if it is, using
1384
- // the vtable is fine. If it is not, using the vtable
1385
- // is good. A win win!
1386
- true
1387
- }
1388
- ( & DefaultImplCandidate ( _) , _) => {
1389
- // Prefer other candidates over default implementations.
1390
- self . tcx ( ) . sess . bug (
1391
- "default implementations shouldn't be recorded \
1392
- when there are other valid candidates") ;
1393
- }
1394
- ( & ProjectionCandidate , & ParamCandidate ( _) ) => {
1395
- // FIXME(#20297) -- this gives where clauses precedent
1396
- // over projections. Really these are just two means
1397
- // of deducing information (one based on the where
1398
- // clauses on the trait definition; one based on those
1399
- // on the enclosing scope), and it'd be better to
1400
- // integrate them more intelligently. But for now this
1401
- // seems ok. If we DON'T give where clauses
1402
- // precedence, we run into trouble in default methods,
1403
- // where both the projection bounds for `Self::A` and
1404
- // the where clauses are in scope.
1405
- true
1406
- }
1407
- _ => {
1408
- false
1409
- }
1415
+ match other {
1416
+ & ObjectCandidate ( ..) |
1417
+ & ParamCandidate ( _) | & ProjectionCandidate => match victim {
1418
+ & DefaultImplCandidate ( ..) => {
1419
+ self . tcx ( ) . sess . bug (
1420
+ "default implementations shouldn't be recorded \
1421
+ when there are other valid candidates") ;
1422
+ }
1423
+ & PhantomFnCandidate => {
1424
+ self . tcx ( ) . sess . bug ( "PhantomFn didn't short-circuit selection" ) ;
1425
+ }
1426
+ & ImplCandidate ( ..) |
1427
+ & ClosureCandidate ( ..) |
1428
+ & FnPointerCandidate ( ..) |
1429
+ & BuiltinObjectCandidate ( ..) |
1430
+ & DefaultImplObjectCandidate ( ..) |
1431
+ & BuiltinCandidate ( ..) => {
1432
+ // We have a where-clause so don't go around looking
1433
+ // for impls.
1434
+ true
1435
+ }
1436
+ & ObjectCandidate ( ..) |
1437
+ & ProjectionCandidate => {
1438
+ // Arbitrarily give param candidates priority
1439
+ // over projection and object candidates.
1440
+ true
1441
+ } ,
1442
+ & ParamCandidate ( ..) => false ,
1443
+ & ErrorCandidate => false // propagate errors
1444
+ } ,
1445
+ _ => false
1410
1446
}
1411
1447
}
1412
1448
0 commit comments