Auto merge of #86866 - nikomatsakis:issue-84841, r=oli-obk
Hack: Ignore inference variables in certain queries Fixes #84841 Fixes #86753 Some queries are not built to accept types with inference variables, which can lead to ICEs. These queries probably ought to be converted to canonical form, but as a quick workaround, we can return conservative results in the case that inference variables are found. We should file a follow-up issue (and update the FIXMEs...) to do the proper refactoring. cc `@arora-aman` r? `@oli-obk`
This commit is contained in:
commit
23c652dfe3
13 changed files with 168 additions and 58 deletions
|
@ -46,13 +46,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||||
{
|
{
|
||||||
self.tcx.sess.perf_stats.queries_canonicalized.fetch_add(1, Ordering::Relaxed);
|
self.tcx.sess.perf_stats.queries_canonicalized.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
||||||
Canonicalizer::canonicalize(
|
Canonicalizer::canonicalize(value, self, self.tcx, &CanonicalizeAllFreeRegions, query_state)
|
||||||
value,
|
|
||||||
Some(self),
|
|
||||||
self.tcx,
|
|
||||||
&CanonicalizeAllFreeRegions,
|
|
||||||
query_state,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Canonicalizes a query *response* `V`. When we canonicalize a
|
/// Canonicalizes a query *response* `V`. When we canonicalize a
|
||||||
|
@ -87,7 +81,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||||
let mut query_state = OriginalQueryValues::default();
|
let mut query_state = OriginalQueryValues::default();
|
||||||
Canonicalizer::canonicalize(
|
Canonicalizer::canonicalize(
|
||||||
value,
|
value,
|
||||||
Some(self),
|
self,
|
||||||
self.tcx,
|
self.tcx,
|
||||||
&CanonicalizeQueryResponse,
|
&CanonicalizeQueryResponse,
|
||||||
&mut query_state,
|
&mut query_state,
|
||||||
|
@ -101,7 +95,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||||
let mut query_state = OriginalQueryValues::default();
|
let mut query_state = OriginalQueryValues::default();
|
||||||
Canonicalizer::canonicalize(
|
Canonicalizer::canonicalize(
|
||||||
value,
|
value,
|
||||||
Some(self),
|
self,
|
||||||
self.tcx,
|
self.tcx,
|
||||||
&CanonicalizeUserTypeAnnotation,
|
&CanonicalizeUserTypeAnnotation,
|
||||||
&mut query_state,
|
&mut query_state,
|
||||||
|
@ -133,7 +127,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||||
|
|
||||||
Canonicalizer::canonicalize(
|
Canonicalizer::canonicalize(
|
||||||
value,
|
value,
|
||||||
Some(self),
|
self,
|
||||||
self.tcx,
|
self.tcx,
|
||||||
&CanonicalizeFreeRegionsOtherThanStatic,
|
&CanonicalizeFreeRegionsOtherThanStatic,
|
||||||
query_state,
|
query_state,
|
||||||
|
@ -275,7 +269,7 @@ impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Canonicalizer<'cx, 'tcx> {
|
struct Canonicalizer<'cx, 'tcx> {
|
||||||
infcx: Option<&'cx InferCtxt<'cx, 'tcx>>,
|
infcx: &'cx InferCtxt<'cx, 'tcx>,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
variables: SmallVec<[CanonicalVarInfo<'tcx>; 8]>,
|
variables: SmallVec<[CanonicalVarInfo<'tcx>; 8]>,
|
||||||
query_state: &'cx mut OriginalQueryValues<'tcx>,
|
query_state: &'cx mut OriginalQueryValues<'tcx>,
|
||||||
|
@ -316,7 +310,6 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
|
||||||
ty::ReVar(vid) => {
|
ty::ReVar(vid) => {
|
||||||
let resolved_vid = self
|
let resolved_vid = self
|
||||||
.infcx
|
.infcx
|
||||||
.unwrap()
|
|
||||||
.inner
|
.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.unwrap_region_constraints()
|
.unwrap_region_constraints()
|
||||||
|
@ -343,7 +336,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
|
||||||
match *t.kind() {
|
match *t.kind() {
|
||||||
ty::Infer(ty::TyVar(vid)) => {
|
ty::Infer(ty::TyVar(vid)) => {
|
||||||
debug!("canonical: type var found with vid {:?}", vid);
|
debug!("canonical: type var found with vid {:?}", vid);
|
||||||
match self.infcx.unwrap().probe_ty_var(vid) {
|
match self.infcx.probe_ty_var(vid) {
|
||||||
// `t` could be a float / int variable; canonicalize that instead.
|
// `t` could be a float / int variable; canonicalize that instead.
|
||||||
Ok(t) => {
|
Ok(t) => {
|
||||||
debug!("(resolved to {:?})", t);
|
debug!("(resolved to {:?})", t);
|
||||||
|
@ -429,7 +422,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
|
||||||
match ct.val {
|
match ct.val {
|
||||||
ty::ConstKind::Infer(InferConst::Var(vid)) => {
|
ty::ConstKind::Infer(InferConst::Var(vid)) => {
|
||||||
debug!("canonical: const var found with vid {:?}", vid);
|
debug!("canonical: const var found with vid {:?}", vid);
|
||||||
match self.infcx.unwrap().probe_const_var(vid) {
|
match self.infcx.probe_const_var(vid) {
|
||||||
Ok(c) => {
|
Ok(c) => {
|
||||||
debug!("(resolved to {:?})", c);
|
debug!("(resolved to {:?})", c);
|
||||||
return self.fold_const(c);
|
return self.fold_const(c);
|
||||||
|
@ -476,7 +469,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
||||||
/// `canonicalize_query` and `canonicalize_response`.
|
/// `canonicalize_query` and `canonicalize_response`.
|
||||||
fn canonicalize<V>(
|
fn canonicalize<V>(
|
||||||
value: V,
|
value: V,
|
||||||
infcx: Option<&InferCtxt<'_, 'tcx>>,
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
canonicalize_region_mode: &dyn CanonicalizeRegionMode,
|
canonicalize_region_mode: &dyn CanonicalizeRegionMode,
|
||||||
query_state: &mut OriginalQueryValues<'tcx>,
|
query_state: &mut OriginalQueryValues<'tcx>,
|
||||||
|
@ -610,7 +603,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
||||||
|
|
||||||
/// Returns the universe in which `vid` is defined.
|
/// Returns the universe in which `vid` is defined.
|
||||||
fn region_var_universe(&self, vid: ty::RegionVid) -> ty::UniverseIndex {
|
fn region_var_universe(&self, vid: ty::RegionVid) -> ty::UniverseIndex {
|
||||||
self.infcx.unwrap().inner.borrow_mut().unwrap_region_constraints().var_universe(vid)
|
self.infcx.inner.borrow_mut().unwrap_region_constraints().var_universe(vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a canonical variable (with the given `info`)
|
/// Creates a canonical variable (with the given `info`)
|
||||||
|
@ -631,7 +624,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
||||||
/// *that*. Otherwise, create a new canonical variable for
|
/// *that*. Otherwise, create a new canonical variable for
|
||||||
/// `ty_var`.
|
/// `ty_var`.
|
||||||
fn canonicalize_ty_var(&mut self, info: CanonicalVarInfo<'tcx>, ty_var: Ty<'tcx>) -> Ty<'tcx> {
|
fn canonicalize_ty_var(&mut self, info: CanonicalVarInfo<'tcx>, ty_var: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
let infcx = self.infcx.expect("encountered ty-var without infcx");
|
let infcx = self.infcx;
|
||||||
let bound_to = infcx.shallow_resolve(ty_var);
|
let bound_to = infcx.shallow_resolve(ty_var);
|
||||||
if bound_to != ty_var {
|
if bound_to != ty_var {
|
||||||
self.fold_ty(bound_to)
|
self.fold_ty(bound_to)
|
||||||
|
@ -650,7 +643,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
|
||||||
info: CanonicalVarInfo<'tcx>,
|
info: CanonicalVarInfo<'tcx>,
|
||||||
const_var: &'tcx ty::Const<'tcx>,
|
const_var: &'tcx ty::Const<'tcx>,
|
||||||
) -> &'tcx ty::Const<'tcx> {
|
) -> &'tcx ty::Const<'tcx> {
|
||||||
let infcx = self.infcx.expect("encountered const-var without infcx");
|
let infcx = self.infcx;
|
||||||
let bound_to = infcx.shallow_resolve(const_var);
|
let bound_to = infcx.shallow_resolve(const_var);
|
||||||
if bound_to != const_var {
|
if bound_to != const_var {
|
||||||
self.fold_const(bound_to)
|
self.fold_const(bound_to)
|
||||||
|
|
|
@ -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 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,23 +88,32 @@ struct NormalizeAfterErasingRegionsFolder<'tcx> {
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> {
|
||||||
|
fn normalize_generic_arg_after_erasing_regions(
|
||||||
|
&self,
|
||||||
|
arg: ty::GenericArg<'tcx>,
|
||||||
|
) -> ty::GenericArg<'tcx> {
|
||||||
|
let arg = self.param_env.and(arg);
|
||||||
|
self.tcx.normalize_generic_arg_after_erasing_regions(arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
|
impl TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
|
||||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||||
self.tcx
|
self.tcx
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||||
let arg = self.param_env.and(ty.into());
|
self.normalize_generic_arg_after_erasing_regions(ty.into()).expect_ty()
|
||||||
self.tcx.normalize_generic_arg_after_erasing_regions(arg).expect_ty()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
|
fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
|
||||||
let arg = self.param_env.and(c.into());
|
self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const()
|
||||||
self.tcx.normalize_generic_arg_after_erasing_regions(arg).expect_const()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
|
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
|
||||||
|
// FIXME: This *probably* needs canonicalization too!
|
||||||
let arg = self.param_env.and(c);
|
let arg = self.param_env.and(c);
|
||||||
self.tcx.normalize_mir_const_after_erasing_regions(arg)
|
self.tcx.normalize_mir_const_after_erasing_regions(arg)
|
||||||
}
|
}
|
||||||
|
|
|
@ -816,6 +816,15 @@ impl<'tcx> ty::TyS<'tcx> {
|
||||||
[component_ty] => component_ty,
|
[component_ty] => component_ty,
|
||||||
_ => self,
|
_ => self,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// FIXME(#86868): We should be canonicalizing, or else moving this to a method of inference
|
||||||
|
// context, or *something* like that, but for now just avoid passing inference
|
||||||
|
// variables to queries that can't cope with them. Instead, conservatively
|
||||||
|
// return "true" (may change drop order).
|
||||||
|
if query_ty.needs_infer() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// This doesn't depend on regions, so try to minimize distinct
|
// This doesn't depend on regions, so try to minimize distinct
|
||||||
// query keys used.
|
// query keys used.
|
||||||
let erased = tcx.normalize_erasing_regions(param_env, query_ty);
|
let erased = tcx.normalize_erasing_regions(param_env, query_ty);
|
||||||
|
|
|
@ -9,7 +9,7 @@ use rustc_middle::mir::{
|
||||||
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
|
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
|
||||||
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
|
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TypeFoldable};
|
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
|
||||||
use rustc_span::source_map::DesugaringKind;
|
use rustc_span::source_map::DesugaringKind;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
|
@ -1329,9 +1329,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
let return_ty = tcx.erase_regions(return_ty);
|
let return_ty = tcx.erase_regions(return_ty);
|
||||||
|
|
||||||
// to avoid panics
|
// to avoid panics
|
||||||
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(
|
||||||
|
@ -1344,7 +1345,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Some(err)
|
Some(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(#86868): 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) {
|
||||||
|
|
|
@ -440,16 +440,10 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||||
let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
|
let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
|
||||||
let expr_ty = fcx.tcx.erase_regions(expr_ty);
|
let expr_ty = fcx.tcx.erase_regions(expr_ty);
|
||||||
let ty_params = fcx.tcx.mk_substs_trait(expr_ty, &[]);
|
let ty_params = fcx.tcx.mk_substs_trait(expr_ty, &[]);
|
||||||
// Check for infer types because cases like `Option<{integer}>` would
|
if fcx
|
||||||
// panic otherwise.
|
.tcx
|
||||||
if !expr_ty.has_infer_types()
|
.type_implements_trait((from_trait, ty, ty_params, fcx.param_env))
|
||||||
&& !ty.has_infer_types()
|
.must_apply_modulo_regions()
|
||||||
&& fcx.tcx.type_implements_trait((
|
|
||||||
from_trait,
|
|
||||||
ty,
|
|
||||||
ty_params,
|
|
||||||
fcx.param_env,
|
|
||||||
))
|
|
||||||
{
|
{
|
||||||
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);
|
||||||
|
|
16
src/test/ui/async-await/issue-84841.rs
Normal file
16
src/test/ui/async-await/issue-84841.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// edition:2018
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn foo() {
|
||||||
|
// Adding an .await here avoids the ICE
|
||||||
|
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
|
||||||
|
async fn test<const N: usize>() {
|
||||||
|
}
|
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`.
|
|
@ -0,0 +1,34 @@
|
||||||
|
// edition:2018
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![warn(rust_2021_compatibility)]
|
||||||
|
|
||||||
|
use std::future::Future;
|
||||||
|
|
||||||
|
struct Runtime;
|
||||||
|
|
||||||
|
impl Runtime {
|
||||||
|
pub fn block_on<F: Future>(&self, _future: F) -> F::Output {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn http<F, Fut>(_func: F)
|
||||||
|
where
|
||||||
|
F: Fn() -> Fut,
|
||||||
|
Fut: Future<Output = ()>,
|
||||||
|
{
|
||||||
|
let rt = Runtime {};
|
||||||
|
let srv = rt.block_on(async move { serve(move || async move { unimplemented!() }) });
|
||||||
|
let _ = || rt.block_on(async { srv });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Server<S> {
|
||||||
|
_marker: std::marker::PhantomData<S>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serve<S>(_new_service: S) -> Server<S> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() { }
|
|
@ -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`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue