Skip to content

Commit 40ee019

Browse files
committed
allow inference vars in type_implements_trait
1 parent 26f7030 commit 40ee019

File tree

9 files changed

+118
-46
lines changed

9 files changed

+118
-46
lines changed

compiler/rustc_middle/src/query/mod.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1559,9 +1559,22 @@ rustc_queries! {
15591559
desc { "evaluating trait selection obligation `{}`", goal.value }
15601560
}
15611561

1562+
/// Evaluates whether the given type implements the given trait
1563+
/// in the given environment.
1564+
///
1565+
/// The inputs are:
1566+
///
1567+
/// - the def-id of the trait
1568+
/// - the self type
1569+
/// - the *other* type parameters of the trait, excluding the self-type
1570+
/// - the parameter environment
1571+
///
1572+
/// FIXME. If the type, trait, or environment has inference variables,
1573+
/// this yields `EvaluatedToUnknown`. It should be refactored
1574+
/// to use canonicalization, really.
15621575
query type_implements_trait(
15631576
key: (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>, )
1564-
) -> bool {
1577+
) -> traits::EvaluationResult {
15651578
desc { "evaluating `type_implements_trait` `{:?}`", key }
15661579
}
15671580

compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1331,7 +1331,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
13311331
// to avoid panics
13321332
if !return_ty.has_infer_types() {
13331333
if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) {
1334-
if tcx.type_implements_trait((iter_trait, return_ty, ty_params, self.param_env))
1334+
if tcx
1335+
.type_implements_trait((iter_trait, return_ty, ty_params, self.param_env))
1336+
.must_apply_modulo_regions()
13351337
{
13361338
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) {
13371339
err.span_suggestion_hidden(

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2396,7 +2396,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
23962396
normalized_ty,
23972397
);
23982398
debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation);
2399-
if self.predicate_may_hold(&try_obligation) && impls_future {
2399+
if self.predicate_may_hold(&try_obligation)
2400+
&& impls_future.must_apply_modulo_regions()
2401+
{
24002402
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
24012403
if snippet.ends_with('?') {
24022404
err.span_suggestion_verbose(

compiler/rustc_trait_selection/src/traits/mod.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -542,8 +542,7 @@ fn vtable_trait_first_method_offset<'tcx>(
542542
}
543543

544544
/// Check whether a `ty` implements given trait(trait_def_id).
545-
///
546-
/// NOTE: Always return `false` for a type which needs inference.
545+
/// See query definition for details.
547546
fn type_implements_trait<'tcx>(
548547
tcx: TyCtxt<'tcx>,
549548
key: (
@@ -552,7 +551,7 @@ fn type_implements_trait<'tcx>(
552551
SubstsRef<'tcx>,
553552
ParamEnv<'tcx>,
554553
),
555-
) -> bool {
554+
) -> EvaluationResult {
556555
let (trait_def_id, ty, params, param_env) = key;
557556

558557
debug!(
@@ -562,13 +561,22 @@ fn type_implements_trait<'tcx>(
562561

563562
let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, params) };
564563

564+
// FIXME: If there are inference variables anywhere, just give up and assume
565+
// we don't know the answer. This works around the ICEs that would result from
566+
// using those inference variables within the `infer_ctxt` we create below.
567+
// Really we should be using canonicalized variables, or perhaps removing
568+
// this query altogether.
569+
if (trait_ref, param_env).needs_infer() {
570+
return EvaluationResult::EvaluatedToUnknown;
571+
}
572+
565573
let obligation = Obligation {
566574
cause: ObligationCause::dummy(),
567575
param_env,
568576
recursion_depth: 0,
569577
predicate: trait_ref.without_const().to_predicate(tcx),
570578
};
571-
tcx.infer_ctxt().enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
579+
tcx.infer_ctxt().enter(|infcx| infcx.evaluate_obligation_no_overflow(&obligation))
572580
}
573581

574582
pub fn provide(providers: &mut ty::query::Providers) {

compiler/rustc_typeck/src/check/cast.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -444,12 +444,15 @@ impl<'a, 'tcx> CastCheck<'tcx> {
444444
// panic otherwise.
445445
if !expr_ty.has_infer_types()
446446
&& !ty.has_infer_types()
447-
&& fcx.tcx.type_implements_trait((
448-
from_trait,
449-
ty,
450-
ty_params,
451-
fcx.param_env,
452-
))
447+
&& fcx
448+
.tcx
449+
.type_implements_trait((
450+
from_trait,
451+
ty,
452+
ty_params,
453+
fcx.param_env,
454+
))
455+
.must_apply_modulo_regions()
453456
{
454457
label = false;
455458
err.span_suggestion(

compiler/rustc_typeck/src/check/upvar.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -961,12 +961,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
961961
let is_drop_defined_for_ty = |ty: Ty<'tcx>| {
962962
let drop_trait = self.tcx.require_lang_item(hir::LangItem::Drop, Some(closure_span));
963963
let ty_params = self.tcx.mk_substs_trait(base_path_ty, &[]);
964-
self.tcx.type_implements_trait((
965-
drop_trait,
966-
ty,
967-
ty_params,
968-
self.tcx.param_env(closure_def_id.expect_local()),
969-
))
964+
self.tcx
965+
.type_implements_trait((
966+
drop_trait,
967+
ty,
968+
ty_params,
969+
self.tcx.param_env(closure_def_id.expect_local()),
970+
))
971+
.must_apply_modulo_regions()
970972
};
971973

972974
let is_drop_defined_for_ty = is_drop_defined_for_ty(base_path_ty);

src/test/ui/async-await/issue-84841.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
// edition:2018
22

3-
async fn main() {
3+
fn main() {
4+
5+
}
6+
7+
async fn foo() {
48
// Adding an .await here avoids the ICE
59
test()?;
10+
//~^ ERROR the `?` operator can only be applied to values that implement `Try`
11+
//~| ERROR the `?` operator can only be used in an async function that returns
612
}
713

814
// Removing the const generic parameter here avoids the ICE
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error[E0277]: the `?` operator can only be applied to values that implement `Try`
2+
--> $DIR/issue-84841.rs:9:5
3+
|
4+
LL | test()?;
5+
| ^^^^^^^ the `?` operator cannot be applied to type `impl Future`
6+
|
7+
= help: the trait `Try` is not implemented for `impl Future`
8+
= note: required by `branch`
9+
10+
error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`)
11+
--> $DIR/issue-84841.rs:9:11
12+
|
13+
LL | async fn foo() {
14+
| ________________-
15+
LL | | // Adding an .await here avoids the ICE
16+
LL | | test()?;
17+
| | ^ cannot use the `?` operator in an async function that returns `()`
18+
LL | |
19+
LL | |
20+
LL | | }
21+
| |_- this function should return `Result` or `Option` to accept `?`
22+
|
23+
= help: the trait `FromResidual<_>` is not implemented for `()`
24+
= note: required by `from_residual`
25+
26+
error: aborting due to 2 previous errors
27+
28+
For more information about this error, try `rustc --explain E0277`.

src/tools/clippy/clippy_utils/src/ty.rs

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@ pub fn implements_trait<'tcx>(
128128
return false;
129129
}
130130
let ty_params = cx.tcx.mk_substs(ty_params.iter());
131-
cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env))
131+
cx.tcx
132+
.type_implements_trait((trait_id, ty, ty_params, cx.param_env))
133+
.must_apply_modulo_regions()
132134
}
133135

134136
/// Checks whether this type implements `Drop`.
@@ -144,22 +146,26 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
144146
match ty.kind() {
145147
ty::Adt(adt, _) => must_use_attr(cx.tcx.get_attrs(adt.did)).is_some(),
146148
ty::Foreign(ref did) => must_use_attr(cx.tcx.get_attrs(*did)).is_some(),
147-
ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
149+
ty::Slice(ty)
150+
| ty::Array(ty, _)
151+
| ty::RawPtr(ty::TypeAndMut { ty, .. })
152+
| ty::Ref(_, ty, _) => {
148153
// for the Array case we don't need to care for the len == 0 case
149154
// because we don't want to lint functions returning empty arrays
150155
is_must_use_ty(cx, *ty)
151-
},
156+
}
152157
ty::Tuple(substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
153158
ty::Opaque(ref def_id, _) => {
154159
for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
155-
if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder() {
160+
if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder()
161+
{
156162
if must_use_attr(cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
157163
return true;
158164
}
159165
}
160166
}
161167
false
162-
},
168+
}
163169
ty::Dynamic(binder, _) => {
164170
for predicate in binder.iter() {
165171
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
@@ -169,7 +175,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
169175
}
170176
}
171177
false
172-
},
178+
}
173179
_ => false,
174180
}
175181
}
@@ -179,7 +185,11 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
179185
// not succeed
180186
/// Checks if `Ty` is normalizable. This function is useful
181187
/// to avoid crashes on `layout_of`.
182-
pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
188+
pub fn is_normalizable<'tcx>(
189+
cx: &LateContext<'tcx>,
190+
param_env: ty::ParamEnv<'tcx>,
191+
ty: Ty<'tcx>,
192+
) -> bool {
183193
is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default())
184194
}
185195

@@ -199,15 +209,14 @@ fn is_normalizable_helper<'tcx>(
199209
if infcx.at(&cause, param_env).normalize(ty).is_ok() {
200210
match ty.kind() {
201211
ty::Adt(def, substs) => def.variants.iter().all(|variant| {
202-
variant
203-
.fields
204-
.iter()
205-
.all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache))
212+
variant.fields.iter().all(|field| {
213+
is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache)
214+
})
206215
}),
207216
_ => ty.walk().all(|generic_arg| match generic_arg.unpack() {
208217
GenericArgKind::Type(inner_ty) if inner_ty != ty => {
209218
is_normalizable_helper(cx, param_env, inner_ty, cache)
210-
},
219+
}
211220
_ => true, // if inner_ty == ty, we've already checked it
212221
}),
213222
}
@@ -225,7 +234,9 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool {
225234
match ty.kind() {
226235
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true,
227236
ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true,
228-
ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type),
237+
ty::Array(inner_type, _) | ty::Slice(inner_type) => {
238+
is_recursively_primitive_type(inner_type)
239+
}
229240
ty::Tuple(inner_types) => inner_types.types().all(is_recursively_primitive_type),
230241
_ => false,
231242
}
@@ -269,11 +280,7 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool {
269280
/// removed.
270281
pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) {
271282
fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) {
272-
if let ty::Ref(_, ty, _) = ty.kind() {
273-
peel(ty, count + 1)
274-
} else {
275-
(ty, count)
276-
}
283+
if let ty::Ref(_, ty, _) = ty.kind() { peel(ty, count + 1) } else { (ty, count) }
277284
}
278285
peel(ty, 0)
279286
}
@@ -328,17 +335,18 @@ pub fn same_type_and_consts(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
328335
return false;
329336
}
330337

331-
substs_a
332-
.iter()
333-
.zip(substs_b.iter())
334-
.all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) {
335-
(GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b,
338+
substs_a.iter().zip(substs_b.iter()).all(|(arg_a, arg_b)| {
339+
match (arg_a.unpack(), arg_b.unpack()) {
340+
(GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => {
341+
inner_a == inner_b
342+
}
336343
(GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => {
337344
same_type_and_consts(type_a, type_b)
338-
},
345+
}
339346
_ => true,
340-
})
341-
},
347+
}
348+
})
349+
}
342350
_ => a == b,
343351
}
344352
}

0 commit comments

Comments
 (0)