mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-04 19:29:07 +00:00
allow inference vars in type_implements_trait
This commit is contained in:
parent
26f7030b16
commit
40ee019c17
@ -1559,9 +1559,22 @@ rustc_queries! {
|
|||||||
desc { "evaluating trait selection obligation `{}`", goal.value }
|
desc { "evaluating trait selection obligation `{}`", goal.value }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evaluates whether the given type implements the given trait
|
||||||
|
/// in the given environment.
|
||||||
|
///
|
||||||
|
/// The inputs are:
|
||||||
|
///
|
||||||
|
/// - the def-id of the trait
|
||||||
|
/// - the self type
|
||||||
|
/// - the *other* type parameters of the trait, excluding the self-type
|
||||||
|
/// - the parameter environment
|
||||||
|
///
|
||||||
|
/// FIXME. If the type, trait, or environment has inference variables,
|
||||||
|
/// this yields `EvaluatedToUnknown`. It should be refactored
|
||||||
|
/// to use canonicalization, really.
|
||||||
query type_implements_trait(
|
query type_implements_trait(
|
||||||
key: (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>, )
|
key: (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>, )
|
||||||
) -> bool {
|
) -> traits::EvaluationResult {
|
||||||
desc { "evaluating `type_implements_trait` `{:?}`", key }
|
desc { "evaluating `type_implements_trait` `{:?}`", key }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1331,7 +1331,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
// to avoid panics
|
// to avoid panics
|
||||||
if !return_ty.has_infer_types() {
|
if !return_ty.has_infer_types() {
|
||||||
if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) {
|
if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) {
|
||||||
if tcx.type_implements_trait((iter_trait, return_ty, ty_params, self.param_env))
|
if tcx
|
||||||
|
.type_implements_trait((iter_trait, return_ty, ty_params, self.param_env))
|
||||||
|
.must_apply_modulo_regions()
|
||||||
{
|
{
|
||||||
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) {
|
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) {
|
||||||
err.span_suggestion_hidden(
|
err.span_suggestion_hidden(
|
||||||
|
@ -2396,7 +2396,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
|||||||
normalized_ty,
|
normalized_ty,
|
||||||
);
|
);
|
||||||
debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation);
|
debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation);
|
||||||
if self.predicate_may_hold(&try_obligation) && impls_future {
|
if self.predicate_may_hold(&try_obligation)
|
||||||
|
&& impls_future.must_apply_modulo_regions()
|
||||||
|
{
|
||||||
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
|
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
|
||||||
if snippet.ends_with('?') {
|
if snippet.ends_with('?') {
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
|
@ -542,8 +542,7 @@ fn vtable_trait_first_method_offset<'tcx>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether a `ty` implements given trait(trait_def_id).
|
/// Check whether a `ty` implements given trait(trait_def_id).
|
||||||
///
|
/// See query definition for details.
|
||||||
/// NOTE: Always return `false` for a type which needs inference.
|
|
||||||
fn type_implements_trait<'tcx>(
|
fn type_implements_trait<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
key: (
|
key: (
|
||||||
@ -552,7 +551,7 @@ fn type_implements_trait<'tcx>(
|
|||||||
SubstsRef<'tcx>,
|
SubstsRef<'tcx>,
|
||||||
ParamEnv<'tcx>,
|
ParamEnv<'tcx>,
|
||||||
),
|
),
|
||||||
) -> bool {
|
) -> EvaluationResult {
|
||||||
let (trait_def_id, ty, params, param_env) = key;
|
let (trait_def_id, ty, params, param_env) = key;
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
@ -562,13 +561,22 @@ fn type_implements_trait<'tcx>(
|
|||||||
|
|
||||||
let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, params) };
|
let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, params) };
|
||||||
|
|
||||||
|
// FIXME: If there are inference variables anywhere, just give up and assume
|
||||||
|
// we don't know the answer. This works around the ICEs that would result from
|
||||||
|
// using those inference variables within the `infer_ctxt` we create below.
|
||||||
|
// Really we should be using canonicalized variables, or perhaps removing
|
||||||
|
// this query altogether.
|
||||||
|
if (trait_ref, param_env).needs_infer() {
|
||||||
|
return EvaluationResult::EvaluatedToUnknown;
|
||||||
|
}
|
||||||
|
|
||||||
let obligation = Obligation {
|
let obligation = Obligation {
|
||||||
cause: ObligationCause::dummy(),
|
cause: ObligationCause::dummy(),
|
||||||
param_env,
|
param_env,
|
||||||
recursion_depth: 0,
|
recursion_depth: 0,
|
||||||
predicate: trait_ref.without_const().to_predicate(tcx),
|
predicate: trait_ref.without_const().to_predicate(tcx),
|
||||||
};
|
};
|
||||||
tcx.infer_ctxt().enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
|
tcx.infer_ctxt().enter(|infcx| infcx.evaluate_obligation_no_overflow(&obligation))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn provide(providers: &mut ty::query::Providers) {
|
pub fn provide(providers: &mut ty::query::Providers) {
|
||||||
|
@ -444,12 +444,15 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||||||
// panic otherwise.
|
// panic otherwise.
|
||||||
if !expr_ty.has_infer_types()
|
if !expr_ty.has_infer_types()
|
||||||
&& !ty.has_infer_types()
|
&& !ty.has_infer_types()
|
||||||
&& fcx.tcx.type_implements_trait((
|
&& fcx
|
||||||
|
.tcx
|
||||||
|
.type_implements_trait((
|
||||||
from_trait,
|
from_trait,
|
||||||
ty,
|
ty,
|
||||||
ty_params,
|
ty_params,
|
||||||
fcx.param_env,
|
fcx.param_env,
|
||||||
))
|
))
|
||||||
|
.must_apply_modulo_regions()
|
||||||
{
|
{
|
||||||
label = false;
|
label = false;
|
||||||
err.span_suggestion(
|
err.span_suggestion(
|
||||||
|
@ -961,12 +961,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let is_drop_defined_for_ty = |ty: Ty<'tcx>| {
|
let is_drop_defined_for_ty = |ty: Ty<'tcx>| {
|
||||||
let drop_trait = self.tcx.require_lang_item(hir::LangItem::Drop, Some(closure_span));
|
let drop_trait = self.tcx.require_lang_item(hir::LangItem::Drop, Some(closure_span));
|
||||||
let ty_params = self.tcx.mk_substs_trait(base_path_ty, &[]);
|
let ty_params = self.tcx.mk_substs_trait(base_path_ty, &[]);
|
||||||
self.tcx.type_implements_trait((
|
self.tcx
|
||||||
|
.type_implements_trait((
|
||||||
drop_trait,
|
drop_trait,
|
||||||
ty,
|
ty,
|
||||||
ty_params,
|
ty_params,
|
||||||
self.tcx.param_env(closure_def_id.expect_local()),
|
self.tcx.param_env(closure_def_id.expect_local()),
|
||||||
))
|
))
|
||||||
|
.must_apply_modulo_regions()
|
||||||
};
|
};
|
||||||
|
|
||||||
let is_drop_defined_for_ty = is_drop_defined_for_ty(base_path_ty);
|
let is_drop_defined_for_ty = is_drop_defined_for_ty(base_path_ty);
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
// edition:2018
|
// edition:2018
|
||||||
|
|
||||||
async fn main() {
|
fn main() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn foo() {
|
||||||
// Adding an .await here avoids the ICE
|
// Adding an .await here avoids the ICE
|
||||||
test()?;
|
test()?;
|
||||||
|
//~^ ERROR the `?` operator can only be applied to values that implement `Try`
|
||||||
|
//~| ERROR the `?` operator can only be used in an async function that returns
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removing the const generic parameter here avoids the ICE
|
// Removing the const generic parameter here avoids the ICE
|
||||||
|
28
src/test/ui/async-await/issue-84841.stderr
Normal file
28
src/test/ui/async-await/issue-84841.stderr
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
error[E0277]: the `?` operator can only be applied to values that implement `Try`
|
||||||
|
--> $DIR/issue-84841.rs:9:5
|
||||||
|
|
|
||||||
|
LL | test()?;
|
||||||
|
| ^^^^^^^ the `?` operator cannot be applied to type `impl Future`
|
||||||
|
|
|
||||||
|
= help: the trait `Try` is not implemented for `impl Future`
|
||||||
|
= note: required by `branch`
|
||||||
|
|
||||||
|
error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`)
|
||||||
|
--> $DIR/issue-84841.rs:9:11
|
||||||
|
|
|
||||||
|
LL | async fn foo() {
|
||||||
|
| ________________-
|
||||||
|
LL | | // Adding an .await here avoids the ICE
|
||||||
|
LL | | test()?;
|
||||||
|
| | ^ cannot use the `?` operator in an async function that returns `()`
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | }
|
||||||
|
| |_- this function should return `Result` or `Option` to accept `?`
|
||||||
|
|
|
||||||
|
= help: the trait `FromResidual<_>` is not implemented for `()`
|
||||||
|
= note: required by `from_residual`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
@ -128,7 +128,9 @@ pub fn implements_trait<'tcx>(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let ty_params = cx.tcx.mk_substs(ty_params.iter());
|
let ty_params = cx.tcx.mk_substs(ty_params.iter());
|
||||||
cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env))
|
cx.tcx
|
||||||
|
.type_implements_trait((trait_id, ty, ty_params, cx.param_env))
|
||||||
|
.must_apply_modulo_regions()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks whether this type implements `Drop`.
|
/// Checks whether this type implements `Drop`.
|
||||||
@ -144,22 +146,26 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
|||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
ty::Adt(adt, _) => must_use_attr(cx.tcx.get_attrs(adt.did)).is_some(),
|
ty::Adt(adt, _) => must_use_attr(cx.tcx.get_attrs(adt.did)).is_some(),
|
||||||
ty::Foreign(ref did) => must_use_attr(cx.tcx.get_attrs(*did)).is_some(),
|
ty::Foreign(ref did) => must_use_attr(cx.tcx.get_attrs(*did)).is_some(),
|
||||||
ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
|
ty::Slice(ty)
|
||||||
|
| ty::Array(ty, _)
|
||||||
|
| ty::RawPtr(ty::TypeAndMut { ty, .. })
|
||||||
|
| ty::Ref(_, ty, _) => {
|
||||||
// for the Array case we don't need to care for the len == 0 case
|
// for the Array case we don't need to care for the len == 0 case
|
||||||
// because we don't want to lint functions returning empty arrays
|
// because we don't want to lint functions returning empty arrays
|
||||||
is_must_use_ty(cx, *ty)
|
is_must_use_ty(cx, *ty)
|
||||||
},
|
}
|
||||||
ty::Tuple(substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
|
ty::Tuple(substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
|
||||||
ty::Opaque(ref def_id, _) => {
|
ty::Opaque(ref def_id, _) => {
|
||||||
for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
|
for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
|
||||||
if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder() {
|
if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder()
|
||||||
|
{
|
||||||
if must_use_attr(cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
|
if must_use_attr(cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
},
|
}
|
||||||
ty::Dynamic(binder, _) => {
|
ty::Dynamic(binder, _) => {
|
||||||
for predicate in binder.iter() {
|
for predicate in binder.iter() {
|
||||||
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
|
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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
},
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,7 +185,11 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
|||||||
// not succeed
|
// not succeed
|
||||||
/// Checks if `Ty` is normalizable. This function is useful
|
/// Checks if `Ty` is normalizable. This function is useful
|
||||||
/// to avoid crashes on `layout_of`.
|
/// to avoid crashes on `layout_of`.
|
||||||
pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
|
pub fn is_normalizable<'tcx>(
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
) -> bool {
|
||||||
is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default())
|
is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,15 +209,14 @@ fn is_normalizable_helper<'tcx>(
|
|||||||
if infcx.at(&cause, param_env).normalize(ty).is_ok() {
|
if infcx.at(&cause, param_env).normalize(ty).is_ok() {
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
ty::Adt(def, substs) => def.variants.iter().all(|variant| {
|
ty::Adt(def, substs) => def.variants.iter().all(|variant| {
|
||||||
variant
|
variant.fields.iter().all(|field| {
|
||||||
.fields
|
is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache)
|
||||||
.iter()
|
})
|
||||||
.all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache))
|
|
||||||
}),
|
}),
|
||||||
_ => ty.walk().all(|generic_arg| match generic_arg.unpack() {
|
_ => ty.walk().all(|generic_arg| match generic_arg.unpack() {
|
||||||
GenericArgKind::Type(inner_ty) if inner_ty != ty => {
|
GenericArgKind::Type(inner_ty) if inner_ty != ty => {
|
||||||
is_normalizable_helper(cx, param_env, inner_ty, cache)
|
is_normalizable_helper(cx, param_env, inner_ty, cache)
|
||||||
},
|
}
|
||||||
_ => true, // if inner_ty == ty, we've already checked it
|
_ => true, // if inner_ty == ty, we've already checked it
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
@ -225,7 +234,9 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool {
|
|||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true,
|
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true,
|
||||||
ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true,
|
ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true,
|
||||||
ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type),
|
ty::Array(inner_type, _) | ty::Slice(inner_type) => {
|
||||||
|
is_recursively_primitive_type(inner_type)
|
||||||
|
}
|
||||||
ty::Tuple(inner_types) => inner_types.types().all(is_recursively_primitive_type),
|
ty::Tuple(inner_types) => inner_types.types().all(is_recursively_primitive_type),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
@ -269,11 +280,7 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool {
|
|||||||
/// removed.
|
/// removed.
|
||||||
pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) {
|
pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) {
|
||||||
fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) {
|
fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) {
|
||||||
if let ty::Ref(_, ty, _) = ty.kind() {
|
if let ty::Ref(_, ty, _) = ty.kind() { peel(ty, count + 1) } else { (ty, count) }
|
||||||
peel(ty, count + 1)
|
|
||||||
} else {
|
|
||||||
(ty, count)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
peel(ty, 0)
|
peel(ty, 0)
|
||||||
}
|
}
|
||||||
@ -328,17 +335,18 @@ pub fn same_type_and_consts(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
substs_a
|
substs_a.iter().zip(substs_b.iter()).all(|(arg_a, arg_b)| {
|
||||||
.iter()
|
match (arg_a.unpack(), arg_b.unpack()) {
|
||||||
.zip(substs_b.iter())
|
(GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => {
|
||||||
.all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) {
|
inner_a == inner_b
|
||||||
(GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b,
|
}
|
||||||
(GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => {
|
(GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => {
|
||||||
same_type_and_consts(type_a, type_b)
|
same_type_and_consts(type_a, type_b)
|
||||||
},
|
}
|
||||||
_ => true,
|
_ => true,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
_ => a == b,
|
_ => a == b,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user