Lazily resolve type-alias-impl-trait defining uses
by using an opaque type obligation to bubble up comparisons between opaque types and other types Also uses proper obligation causes so that the body id works, because out of some reason nll uses body ids for logic instead of just diagnostics.
This commit is contained in:
parent
8d2b598459
commit
0f6e06b7c0
284 changed files with 2646 additions and 2097 deletions
|
@ -124,8 +124,9 @@ fn mir_borrowck<'tcx>(
|
|||
) -> &'tcx BorrowCheckResult<'tcx> {
|
||||
let (input_body, promoted) = tcx.mir_promoted(def);
|
||||
debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
|
||||
let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
|
||||
|
||||
let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| {
|
||||
let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(hir_owner).enter(|infcx| {
|
||||
let input_body: &Body<'_> = &input_body.borrow();
|
||||
let promoted: &IndexVec<_, _> = &promoted.borrow();
|
||||
do_mir_borrowck(&infcx, input_body, promoted, false).0
|
||||
|
@ -140,7 +141,7 @@ fn mir_borrowck<'tcx>(
|
|||
/// If `return_body_with_facts` is true, then return the body with non-erased
|
||||
/// region ids on which the borrow checking was performed together with Polonius
|
||||
/// facts.
|
||||
#[instrument(skip(infcx, input_body, input_promoted), level = "debug")]
|
||||
#[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.with_opt_param().as_local().unwrap()), level = "debug")]
|
||||
fn do_mir_borrowck<'a, 'tcx>(
|
||||
infcx: &InferCtxt<'a, 'tcx>,
|
||||
input_body: &Body<'tcx>,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::vec_map::VecMap;
|
||||
use rustc_hir::OpaqueTyOrigin;
|
||||
use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
|
||||
|
@ -54,27 +53,40 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
pub(crate) fn infer_opaque_types(
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
|
||||
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, (Ty<'tcx>, Span, OpaqueTyOrigin)>,
|
||||
span: Span,
|
||||
) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> {
|
||||
opaque_ty_decls
|
||||
.into_iter()
|
||||
.filter_map(|(opaque_type_key, decl)| {
|
||||
.filter_map(|(opaque_type_key, (concrete_type, decl_span, origin))| {
|
||||
let substs = opaque_type_key.substs;
|
||||
let concrete_type = decl.concrete_ty;
|
||||
// FIXME: why are the spans in decl_span often DUMMY_SP?
|
||||
let span = decl_span.substitute_dummy(span);
|
||||
debug!(?concrete_type, ?substs);
|
||||
|
||||
let mut subst_regions = vec![self.universal_regions.fr_static];
|
||||
let universal_substs = infcx.tcx.fold_regions(substs, &mut false, |region, _| {
|
||||
let vid = self.universal_regions.to_region_vid(region);
|
||||
subst_regions.push(vid);
|
||||
self.definitions[vid].external_name.unwrap_or_else(|| {
|
||||
infcx
|
||||
.tcx
|
||||
.sess
|
||||
.delay_span_bug(span, "opaque type with non-universal region substs");
|
||||
infcx.tcx.lifetimes.re_static
|
||||
})
|
||||
let vid = self.to_region_vid(region);
|
||||
trace!(?vid);
|
||||
let scc = self.constraint_sccs.scc(vid);
|
||||
trace!(?scc);
|
||||
match self.scc_values.universal_regions_outlived_by(scc).find_map(|lb| {
|
||||
self.eval_equal(vid, lb).then_some(self.definitions[lb].external_name?)
|
||||
}) {
|
||||
Some(region) => {
|
||||
let vid = self.universal_regions.to_region_vid(region);
|
||||
subst_regions.push(vid);
|
||||
region
|
||||
}
|
||||
None => {
|
||||
subst_regions.push(vid);
|
||||
infcx.tcx.sess.delay_span_bug(
|
||||
span,
|
||||
"opaque type with non-universal region substs",
|
||||
);
|
||||
infcx.tcx.lifetimes.re_static
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
subst_regions.sort();
|
||||
|
@ -100,12 +112,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
span,
|
||||
);
|
||||
|
||||
check_opaque_type_parameter_valid(
|
||||
infcx.tcx,
|
||||
opaque_type_key,
|
||||
OpaqueTypeDecl { concrete_ty: remapped_type, ..decl },
|
||||
)
|
||||
.then_some((opaque_type_key, remapped_type))
|
||||
check_opaque_type_parameter_valid(infcx.tcx, opaque_type_key, origin, span)
|
||||
.then_some((opaque_type_key, remapped_type))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
@ -149,9 +157,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
fn check_opaque_type_parameter_valid(
|
||||
tcx: TyCtxt<'_>,
|
||||
opaque_type_key: OpaqueTypeKey<'_>,
|
||||
decl: OpaqueTypeDecl<'_>,
|
||||
origin: OpaqueTyOrigin,
|
||||
span: Span,
|
||||
) -> bool {
|
||||
match decl.origin {
|
||||
match origin {
|
||||
// No need to check return position impl trait (RPIT)
|
||||
// because for type and const parameters they are correct
|
||||
// by construction: we convert
|
||||
|
@ -177,7 +186,6 @@ fn check_opaque_type_parameter_valid(
|
|||
// Check these
|
||||
OpaqueTyOrigin::TyAlias => {}
|
||||
}
|
||||
let span = decl.definition_span;
|
||||
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
|
||||
let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
|
||||
for (i, arg) in opaque_type_key.substs.iter().enumerate() {
|
||||
|
|
|
@ -147,9 +147,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
// Return types are a bit more complex. They may contain opaque `impl Trait` types.
|
||||
let mir_output_ty = body.local_decls[RETURN_PLACE].ty;
|
||||
let output_span = body.local_decls[RETURN_PLACE].source_info.span;
|
||||
if let Err(terr) = self.eq_opaque_type_and_type(
|
||||
mir_output_ty,
|
||||
if let Err(terr) = self.eq_types(
|
||||
normalized_output_ty,
|
||||
mir_output_ty,
|
||||
Locations::All(output_span),
|
||||
ConstraintCategory::BoringNoLocation,
|
||||
) {
|
||||
|
@ -169,9 +169,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
let user_provided_output_ty = user_provided_sig.output();
|
||||
let user_provided_output_ty =
|
||||
self.normalize(user_provided_output_ty, Locations::All(output_span));
|
||||
if let Err(err) = self.eq_opaque_type_and_type(
|
||||
mir_output_ty,
|
||||
if let Err(err) = self.eq_types(
|
||||
user_provided_output_ty,
|
||||
mir_output_ty,
|
||||
Locations::All(output_span),
|
||||
ConstraintCategory::BoringNoLocation,
|
||||
) {
|
||||
|
|
|
@ -5,6 +5,7 @@ use std::{fmt, iter, mem};
|
|||
|
||||
use either::Either;
|
||||
|
||||
use hir::OpaqueTyOrigin;
|
||||
use rustc_data_structures::frozen::Frozen;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::vec_map::VecMap;
|
||||
|
@ -15,12 +16,9 @@ use rustc_hir::def_id::LocalDefId;
|
|||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_infer::infer::canonical::QueryRegionConstraints;
|
||||
use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
|
||||
use rustc_infer::infer::outlives::env::RegionBoundPairs;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::{
|
||||
InferCtxt, InferOk, LateBoundRegionConversionTime, NllRegionVariableOrigin,
|
||||
};
|
||||
use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime, NllRegionVariableOrigin};
|
||||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::AssertKind;
|
||||
|
@ -41,7 +39,7 @@ use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
|||
use rustc_trait_selection::traits::query::type_op;
|
||||
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
|
||||
use rustc_trait_selection::traits::query::Fallible;
|
||||
use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations};
|
||||
use rustc_trait_selection::traits::{self, ObligationCause};
|
||||
|
||||
use rustc_const_eval::transform::{
|
||||
check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression,
|
||||
|
@ -75,7 +73,7 @@ macro_rules! span_mirbug {
|
|||
$context.last_span,
|
||||
&format!(
|
||||
"broken MIR in {:?} ({:?}): {}",
|
||||
$context.body.source.def_id(),
|
||||
$context.body().source.def_id(),
|
||||
$elem,
|
||||
format_args!($($message)*),
|
||||
),
|
||||
|
@ -193,24 +191,40 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
|||
let opaque_type_values =
|
||||
infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
||||
|
||||
opaque_type_values
|
||||
let opaque_type_values = opaque_type_values
|
||||
.into_iter()
|
||||
.filter_map(|(opaque_type_key, mut decl)| {
|
||||
decl.concrete_ty = infcx.resolve_vars_if_possible(decl.concrete_ty);
|
||||
.filter_map(|(opaque_type_key, decl)| {
|
||||
let def_id = body.source.def_id().expect_local();
|
||||
let body_id = cx.tcx().hir().local_def_id_to_hir_id(def_id);
|
||||
let cause = ObligationCause::misc(body.span, body_id);
|
||||
let hidden = cx
|
||||
.fully_perform_op(
|
||||
Locations::All(body.span),
|
||||
ConstraintCategory::OpaqueType,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
Ok(decl
|
||||
.hidden_type(infcx, &cause, param_env)
|
||||
.map_err(|e| e.0)?)
|
||||
},
|
||||
|| "opaque_type_map".to_string(),
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
let mut hidden_type = infcx.resolve_vars_if_possible(hidden.ty);
|
||||
trace!(
|
||||
"finalized opaque type {:?} to {:#?}",
|
||||
opaque_type_key,
|
||||
decl.concrete_ty.kind()
|
||||
hidden_type.kind()
|
||||
);
|
||||
if decl.concrete_ty.has_infer_types_or_consts() {
|
||||
if hidden_type.has_infer_types_or_consts() {
|
||||
infcx.tcx.sess.delay_span_bug(
|
||||
body.span,
|
||||
&format!("could not resolve {:#?}", decl.concrete_ty.kind()),
|
||||
hidden.span,
|
||||
&format!("could not resolve {:#?}", hidden_type.kind()),
|
||||
);
|
||||
decl.concrete_ty = infcx.tcx.ty_error();
|
||||
hidden_type = infcx.tcx.ty_error();
|
||||
}
|
||||
let concrete_is_opaque = if let ty::Opaque(def_id, _) = decl.concrete_ty.kind()
|
||||
{
|
||||
let concrete_is_opaque = if let ty::Opaque(def_id, _) = hidden_type.kind() {
|
||||
*def_id == opaque_type_key.def_id
|
||||
} else {
|
||||
false
|
||||
|
@ -242,10 +256,15 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
|||
);
|
||||
None
|
||||
} else {
|
||||
Some((opaque_type_key, decl))
|
||||
Some((opaque_type_key, (hidden_type, hidden.span, decl.origin)))
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
.collect();
|
||||
// `hidden_type` may re-register an opaque type, so we need to clean out the
|
||||
// newly re-added types. Either we got here successfully, so they are irrelevant,
|
||||
// or we already errored anyway.
|
||||
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
||||
opaque_type_values
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -275,7 +294,7 @@ fn type_check_internal<'a, 'tcx, R>(
|
|||
borrowck_context,
|
||||
);
|
||||
let errors_reported = {
|
||||
let mut verifier = TypeVerifier::new(&mut checker, body, promoted);
|
||||
let mut verifier = TypeVerifier::new(&mut checker, promoted);
|
||||
verifier.visit_body(&body);
|
||||
verifier.errors_reported
|
||||
};
|
||||
|
@ -332,7 +351,6 @@ enum FieldAccessError {
|
|||
/// is a problem.
|
||||
struct TypeVerifier<'a, 'b, 'tcx> {
|
||||
cx: &'a mut TypeChecker<'b, 'tcx>,
|
||||
body: &'b Body<'tcx>,
|
||||
promoted: &'b IndexVec<Promoted, Body<'tcx>>,
|
||||
last_span: Span,
|
||||
errors_reported: bool,
|
||||
|
@ -468,7 +486,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
|
||||
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
self.super_rvalue(rvalue, location);
|
||||
let rval_ty = rvalue.ty(self.body, self.tcx());
|
||||
let rval_ty = rvalue.ty(self.body(), self.tcx());
|
||||
self.sanitize_type(rvalue, rval_ty);
|
||||
}
|
||||
|
||||
|
@ -527,10 +545,13 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
||||
fn new(
|
||||
cx: &'a mut TypeChecker<'b, 'tcx>,
|
||||
body: &'b Body<'tcx>,
|
||||
promoted: &'b IndexVec<Promoted, Body<'tcx>>,
|
||||
) -> Self {
|
||||
TypeVerifier { body, promoted, cx, last_span: body.span, errors_reported: false }
|
||||
TypeVerifier { promoted, last_span: cx.body.span, cx, errors_reported: false }
|
||||
}
|
||||
|
||||
fn body(&self) -> &Body<'tcx> {
|
||||
self.cx.body
|
||||
}
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
|
@ -555,7 +576,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
) -> PlaceTy<'tcx> {
|
||||
debug!("sanitize_place: {:?}", place);
|
||||
|
||||
let mut place_ty = PlaceTy::from_ty(self.body.local_decls[place.local].ty);
|
||||
let mut place_ty = PlaceTy::from_ty(self.body().local_decls[place.local].ty);
|
||||
|
||||
for elem in place.projection.iter() {
|
||||
if place_ty.variant_index.is_none() {
|
||||
|
@ -600,7 +621,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
// checker on the promoted MIR, then transfer the constraints back to
|
||||
// the main MIR, changing the locations to the provided location.
|
||||
|
||||
let parent_body = mem::replace(&mut self.body, promoted_body);
|
||||
let parent_body = mem::replace(&mut self.cx.body, promoted_body);
|
||||
|
||||
// Use new sets of constraints and closure bounds so that we can
|
||||
// modify their locations.
|
||||
|
@ -636,7 +657,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
self.cx.typeck_mir(promoted_body);
|
||||
}
|
||||
|
||||
self.body = parent_body;
|
||||
self.cx.body = parent_body;
|
||||
// Merge the outlives constraints back in, at the given location.
|
||||
swap_constraints(self);
|
||||
|
||||
|
@ -698,7 +719,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
}))
|
||||
}
|
||||
ProjectionElem::Index(i) => {
|
||||
let index_ty = Place::from(i).ty(self.body, tcx).ty;
|
||||
let index_ty = Place::from(i).ty(self.body(), tcx).ty;
|
||||
if index_ty != tcx.types.usize {
|
||||
PlaceTy::from_ty(span_mirbug_and_err!(self, i, "index by non-usize {:?}", i))
|
||||
} else {
|
||||
|
@ -907,7 +928,7 @@ struct BorrowCheckContext<'a, 'tcx> {
|
|||
crate struct MirTypeckResults<'tcx> {
|
||||
crate constraints: MirTypeckRegionConstraints<'tcx>,
|
||||
crate universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||
crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
|
||||
crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, (Ty<'tcx>, Span, OpaqueTyOrigin)>,
|
||||
}
|
||||
|
||||
/// A collection of region constraints that must be satisfied for the
|
||||
|
@ -1057,17 +1078,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
checker
|
||||
}
|
||||
|
||||
fn body(&self) -> &Body<'tcx> {
|
||||
self.body
|
||||
}
|
||||
|
||||
fn unsized_feature_enabled(&self) -> bool {
|
||||
let features = self.tcx().features();
|
||||
features.unsized_locals || features.unsized_fn_params
|
||||
}
|
||||
|
||||
/// Equate the inferred type and the annotated type for user type annotations
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn check_user_type_annotations(&mut self) {
|
||||
debug!(
|
||||
"check_user_type_annotations: user_type_annotations={:?}",
|
||||
self.user_type_annotations
|
||||
);
|
||||
debug!(?self.user_type_annotations);
|
||||
for user_annotation in self.user_type_annotations {
|
||||
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
|
||||
let inferred_ty = self.normalize(inferred_ty, Locations::All(span));
|
||||
|
@ -1208,130 +1231,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Equates a type `anon_ty` that may contain opaque types whose
|
||||
/// values are to be inferred by the MIR.
|
||||
///
|
||||
/// The type `revealed_ty` contains the same type as `anon_ty`, but with the
|
||||
/// hidden types for impl traits revealed.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Consider a piece of code like
|
||||
///
|
||||
/// ```rust
|
||||
/// type Foo<U> = impl Debug;
|
||||
///
|
||||
/// fn foo<T: Debug>(t: T) -> Box<Foo<T>> {
|
||||
/// Box::new((t, 22_u32))
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Here, the function signature would be something like
|
||||
/// `fn(T) -> Box<impl Debug>`. The MIR return slot would have
|
||||
/// the type with the opaque type revealed, so `Box<(T, u32)>`.
|
||||
///
|
||||
/// In terms of our function parameters:
|
||||
///
|
||||
/// * `anon_ty` would be `Box<Foo<T>>` where `Foo<T>` is an opaque type
|
||||
/// scoped to this function (note that it is parameterized by the
|
||||
/// generics of `foo`). Note that `anon_ty` is not just the opaque type,
|
||||
/// but the entire return type (which may contain opaque types within it).
|
||||
/// * `revealed_ty` would be `Box<(T, u32)>`
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn eq_opaque_type_and_type(
|
||||
&mut self,
|
||||
revealed_ty: Ty<'tcx>,
|
||||
anon_ty: Ty<'tcx>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
) -> Fallible<()> {
|
||||
// Fast path for the common case.
|
||||
if !anon_ty.has_opaque_types() {
|
||||
if let Err(terr) = self.eq_types(anon_ty, revealed_ty, locations, category) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
locations,
|
||||
"eq_opaque_type_and_type: `{:?}=={:?}` failed with `{:?}`",
|
||||
revealed_ty,
|
||||
anon_ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let param_env = self.param_env;
|
||||
let body = self.body;
|
||||
let mir_def_id = body.source.def_id().expect_local();
|
||||
|
||||
debug!(?mir_def_id);
|
||||
self.fully_perform_op(
|
||||
locations,
|
||||
category,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
let mut obligations = ObligationAccumulator::default();
|
||||
|
||||
let dummy_body_id = hir::CRATE_HIR_ID;
|
||||
|
||||
// Replace the opaque types defined by this function with
|
||||
// inference variables, creating a map. In our example above,
|
||||
// this would transform the type `Box<Foo<T>>` (where `Foo` is an opaque type)
|
||||
// to `Box<?T>`, returning an `opaque_type_map` mapping `{Foo<T> -> ?T}`.
|
||||
// (Note that the key of the map is both the def-id of `Foo` along with
|
||||
// any generic parameters.)
|
||||
let output_ty = obligations.add(infcx.instantiate_opaque_types(
|
||||
dummy_body_id,
|
||||
param_env,
|
||||
anon_ty,
|
||||
locations.span(body),
|
||||
));
|
||||
debug!(?output_ty, ?revealed_ty);
|
||||
|
||||
// Make sure that the inferred types are well-formed. I'm
|
||||
// not entirely sure this is needed (the HIR type check
|
||||
// didn't do this) but it seems sensible to prevent opaque
|
||||
// types hiding ill-formed types.
|
||||
obligations.obligations.push(traits::Obligation::new(
|
||||
ObligationCause::dummy(),
|
||||
param_env,
|
||||
ty::Binder::dummy(ty::PredicateKind::WellFormed(revealed_ty.into()))
|
||||
.to_predicate(infcx.tcx),
|
||||
));
|
||||
obligations.add(
|
||||
infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq(output_ty, revealed_ty)?,
|
||||
);
|
||||
|
||||
debug!("equated");
|
||||
|
||||
Ok(InferOk { value: (), obligations: obligations.into_vec() })
|
||||
},
|
||||
|| "input_output".to_string(),
|
||||
),
|
||||
)?;
|
||||
|
||||
// Finally, if we instantiated the anon types successfully, we
|
||||
// have to solve any bounds (e.g., `-> impl Iterator` needs to
|
||||
// prove that `T: Iterator` where `T` is the type we
|
||||
// instantiated it with).
|
||||
for (opaque_type_key, opaque_decl) in self.infcx.opaque_types() {
|
||||
self.fully_perform_op(
|
||||
locations,
|
||||
ConstraintCategory::OpaqueType,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
infcx.constrain_opaque_type(opaque_type_key, &opaque_decl);
|
||||
Ok(InferOk { value: (), obligations: vec![] })
|
||||
},
|
||||
|| "opaque_type_map".to_string(),
|
||||
),
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
@ -1881,6 +1780,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
fn ensure_place_sized(&mut self, ty: Ty<'tcx>, span: Span) {
|
||||
let tcx = self.tcx();
|
||||
|
||||
// This may contain opaque types, resolve them to the underlying
|
||||
// type if defined in the current function. Otherwise we can't
|
||||
// necessarily prove sizedness of the type.
|
||||
let ty = self.infcx.resolve_vars_if_possible(ty);
|
||||
|
||||
// Erase the regions from `ty` to get a global type. The
|
||||
// `Sized` bound in no way depends on precise regions, so this
|
||||
// shouldn't affect `is_sized`.
|
||||
|
@ -2773,20 +2677,3 @@ impl NormalizeLocation for Location {
|
|||
Locations::Single(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct ObligationAccumulator<'tcx> {
|
||||
obligations: PredicateObligations<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> ObligationAccumulator<'tcx> {
|
||||
fn add<T>(&mut self, value: InferOk<'tcx, T>) -> T {
|
||||
let InferOk { value, obligations } = value;
|
||||
self.obligations.extend(obligations);
|
||||
value
|
||||
}
|
||||
|
||||
fn into_vec(self) -> PredicateObligations<'tcx> {
|
||||
self.obligations
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::{self, Const, Ty};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::query::Fallible;
|
||||
|
||||
use crate::constraints::OutlivesConstraint;
|
||||
use crate::diagnostics::UniverseInfo;
|
||||
use crate::type_check::{Locations, TypeChecker};
|
||||
use crate::type_check::{CustomTypeOp, Locations, TypeChecker};
|
||||
|
||||
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
|
||||
|
@ -65,10 +66,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
|
|||
|
||||
impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
|
||||
fn span(&self) -> Span {
|
||||
match self.locations {
|
||||
Locations::All(span) => span,
|
||||
Locations::Single(_) => DUMMY_SP,
|
||||
}
|
||||
self.locations.span(self.type_checker.body)
|
||||
}
|
||||
|
||||
fn param_env(&self) -> ty::ParamEnv<'tcx> {
|
||||
|
@ -137,4 +135,54 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
|
|||
fn forbid_inference_vars() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn constrain_opaque_type(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected: bool) {
|
||||
let param_env = self.param_env();
|
||||
let span = self.span();
|
||||
let def_id = self.type_checker.body.source.def_id().expect_local();
|
||||
let body_id = self.type_checker.tcx().hir().local_def_id_to_hir_id(def_id);
|
||||
let cause = ObligationCause::misc(span, body_id);
|
||||
self.type_checker
|
||||
.fully_perform_op(
|
||||
self.locations,
|
||||
self.category,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
let (concrete_ty, opaque_type_key) =
|
||||
match (a.kind(), b.kind(), a_is_expected) {
|
||||
(ty::Opaque(..), ty::Opaque(..), true) => {
|
||||
(b, a.expect_opaque_type())
|
||||
}
|
||||
(ty::Opaque(..), ty::Opaque(..), false) => {
|
||||
(a, b.expect_opaque_type())
|
||||
}
|
||||
(ty::Opaque(..), _, _) => (b, a.expect_opaque_type()),
|
||||
(_, ty::Opaque(..), _) => (a, b.expect_opaque_type()),
|
||||
_ => span_bug!(
|
||||
span,
|
||||
"no opaque types in constrain_opaque_type {:?}, {:?}",
|
||||
a,
|
||||
b
|
||||
),
|
||||
};
|
||||
let mut result = self.type_checker.infcx.constrain_opaque_type(
|
||||
param_env,
|
||||
opaque_type_key,
|
||||
concrete_ty,
|
||||
span,
|
||||
)?;
|
||||
result.obligations.push(infcx.opaque_ty_obligation(
|
||||
a,
|
||||
b,
|
||||
a_is_expected,
|
||||
param_env,
|
||||
cause,
|
||||
));
|
||||
Ok(result)
|
||||
},
|
||||
|| "constrain_opaque_type".to_string(),
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -728,6 +728,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
|||
self.tcx.fold_regions(value, &mut false, |_region, _depth| self.next_nll_region_var(origin))
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, indices))]
|
||||
fn replace_bound_regions_with_nll_infer_vars<T>(
|
||||
&self,
|
||||
origin: NllRegionVariableOrigin,
|
||||
|
@ -738,22 +739,15 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
|||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
debug!(
|
||||
"replace_bound_regions_with_nll_infer_vars(value={:?}, all_outlive_scope={:?})",
|
||||
value, all_outlive_scope,
|
||||
);
|
||||
let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| {
|
||||
debug!("replace_bound_regions_with_nll_infer_vars: br={:?}", br);
|
||||
debug!(?br);
|
||||
let liberated_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
|
||||
scope: all_outlive_scope.to_def_id(),
|
||||
bound_region: br.kind,
|
||||
}));
|
||||
let region_vid = self.next_nll_region_var(origin);
|
||||
indices.insert_late_bound_region(liberated_region, region_vid.to_region_vid());
|
||||
debug!(
|
||||
"replace_bound_regions_with_nll_infer_vars: liberated_region={:?} => {:?}",
|
||||
liberated_region, region_vid
|
||||
);
|
||||
debug!(?liberated_region, ?region_vid);
|
||||
region_vid
|
||||
});
|
||||
value
|
||||
|
@ -768,6 +762,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
|||
/// entries for them and store them in the indices map. This code iterates over the complete
|
||||
/// set of late-bound regions and checks for any that we have not yet seen, adding them to the
|
||||
/// inputs vector.
|
||||
#[instrument(skip(self, indices))]
|
||||
fn replace_late_bound_regions_with_nll_infer_vars(
|
||||
&self,
|
||||
mir_def_id: LocalDefId,
|
||||
|
@ -779,6 +774,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
|||
debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
|
||||
if !indices.indices.contains_key(&r) {
|
||||
let region_vid = self.next_nll_region_var(FR);
|
||||
debug!(?region_vid);
|
||||
indices.insert_late_bound_region(r, region_vid.to_region_vid());
|
||||
}
|
||||
});
|
||||
|
|
|
@ -11,7 +11,7 @@ use rustc_middle::mir::*;
|
|||
use rustc_middle::ty::cast::CastTy;
|
||||
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
|
||||
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
|
||||
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeFoldable};
|
||||
use rustc_mir_dataflow::{self, Analysis};
|
||||
use rustc_span::{sym, Span, Symbol};
|
||||
use rustc_trait_selection::traits::SelectionContext;
|
||||
|
@ -46,7 +46,10 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
|
|||
location: Location,
|
||||
) -> bool {
|
||||
let ty = ccx.body.local_decls[local].ty;
|
||||
if !NeedsDrop::in_any_value_of_ty(ccx, ty) {
|
||||
// Peeking into opaque types causes cycles if the current function declares said opaque
|
||||
// type. Thus we avoid short circuiting on the type and instead run the more expensive
|
||||
// analysis that looks at the actual usage withhin this function
|
||||
if !ty.has_opaque_types() && !NeedsDrop::in_any_value_of_ty(ccx, ty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -100,7 +103,10 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
|
|||
location: Location,
|
||||
) -> bool {
|
||||
let ty = ccx.body.local_decls[local].ty;
|
||||
if !HasMutInterior::in_any_value_of_ty(ccx, ty) {
|
||||
// Peeking into opaque types causes cycles if the current function declares said opaque
|
||||
// type. Thus we avoid short circuiting on the type and instead run the more expensive
|
||||
// analysis that looks at the actual usage withhin this function
|
||||
if !ty.has_opaque_types() && !HasMutInterior::in_any_value_of_ty(ccx, ty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -148,7 +154,12 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
|
|||
|
||||
// If we know that all values of the return type are structurally matchable, there's no
|
||||
// need to run dataflow.
|
||||
_ if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) => false,
|
||||
// Opaque types do not participate in const generics or pattern matching, so we can safely count them out.
|
||||
_ if ccx.body.return_ty().has_opaque_types()
|
||||
|| !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) =>
|
||||
{
|
||||
false
|
||||
}
|
||||
|
||||
hir::ConstContext::Const | hir::ConstContext::Static(_) => {
|
||||
let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
|
||||
|
@ -395,6 +406,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
|
|||
| ty::PredicateKind::Projection(_)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
|
||||
ty::PredicateKind::ObjectSafe(_) => {
|
||||
bug!("object safe predicate on function: {:#?}", predicate)
|
||||
|
|
|
@ -78,7 +78,6 @@ pub fn equal_up_to_regions<'tcx>(
|
|||
}
|
||||
|
||||
// Normalize lifetimes away on both sides, then compare.
|
||||
let param_env = param_env.with_reveal_all_normalized(tcx);
|
||||
let normalize = |ty: Ty<'tcx>| {
|
||||
tcx.normalize_erasing_regions(
|
||||
param_env,
|
||||
|
@ -169,9 +168,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
return true;
|
||||
}
|
||||
// Normalize projections and things like that.
|
||||
// FIXME: We need to reveal_all, as some optimizations change types in ways
|
||||
// that require unfolding opaque types.
|
||||
let param_env = self.param_env.with_reveal_all_normalized(self.tcx);
|
||||
let param_env = self.param_env;
|
||||
let src = self.tcx.normalize_erasing_regions(param_env, src);
|
||||
let dest = self.tcx.normalize_erasing_regions(param_env, dest);
|
||||
|
||||
|
|
|
@ -44,6 +44,15 @@ where
|
|||
self.0.iter().find(|(key, _)| k == key.borrow()).map(|elem| &elem.1)
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the value in the entry.
|
||||
pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: Eq,
|
||||
{
|
||||
self.0.iter_mut().find(|(key, _)| k == key.borrow()).map(|elem| &mut elem.1)
|
||||
}
|
||||
|
||||
/// Returns the any value corresponding to the supplied predicate filter.
|
||||
///
|
||||
/// The supplied predicate will be applied to each (key, value) pair and it will return a
|
||||
|
@ -63,7 +72,7 @@ where
|
|||
// This should return just one element, otherwise it's a bug
|
||||
assert!(
|
||||
filter.next().is_none(),
|
||||
"Collection {:?} should have just one matching element",
|
||||
"Collection {:#?} should have just one matching element",
|
||||
self
|
||||
);
|
||||
Some(value)
|
||||
|
|
|
@ -34,6 +34,12 @@ pub struct At<'a, 'tcx> {
|
|||
pub infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
pub cause: &'a ObligationCause<'tcx>,
|
||||
pub param_env: ty::ParamEnv<'tcx>,
|
||||
/// Whether we should define opaque types
|
||||
/// or just treat them opaquely.
|
||||
/// Currently only used to prevent predicate
|
||||
/// matching from matching anything against opaque
|
||||
/// types.
|
||||
pub define_opaque_types: bool,
|
||||
}
|
||||
|
||||
pub struct Trace<'a, 'tcx> {
|
||||
|
@ -49,7 +55,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
cause: &'a ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> At<'a, 'tcx> {
|
||||
At { infcx: self, cause, param_env }
|
||||
At { infcx: self, cause, param_env, define_opaque_types: true }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,6 +70,10 @@ pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> At<'a, 'tcx> {
|
||||
pub fn define_opaque_types(self, define_opaque_types: bool) -> Self {
|
||||
Self { define_opaque_types, ..self }
|
||||
}
|
||||
|
||||
/// Hacky routine for equating two impl headers in coherence.
|
||||
pub fn eq_impl_headers(
|
||||
self,
|
||||
|
@ -194,7 +204,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
|
|||
{
|
||||
let Trace { at, trace, a_is_expected } = self;
|
||||
at.infcx.commit_if_ok(|_| {
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env);
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
|
||||
fields
|
||||
.sub(a_is_expected)
|
||||
.relate(a, b)
|
||||
|
@ -211,7 +221,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
|
|||
{
|
||||
let Trace { at, trace, a_is_expected } = self;
|
||||
at.infcx.commit_if_ok(|_| {
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env);
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
|
||||
fields
|
||||
.equate(a_is_expected)
|
||||
.relate(a, b)
|
||||
|
@ -226,7 +236,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
|
|||
{
|
||||
let Trace { at, trace, a_is_expected } = self;
|
||||
at.infcx.commit_if_ok(|_| {
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env);
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
|
||||
fields
|
||||
.lub(a_is_expected)
|
||||
.relate(a, b)
|
||||
|
@ -241,7 +251,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
|
|||
{
|
||||
let Trace { at, trace, a_is_expected } = self;
|
||||
at.infcx.commit_if_ok(|_| {
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env);
|
||||
let mut fields = at.infcx.combine_fields(trace, at.param_env, at.define_opaque_types);
|
||||
fields
|
||||
.glb(a_is_expected)
|
||||
.relate(a, b)
|
||||
|
|
|
@ -25,7 +25,7 @@ use rustc_middle::arena::ArenaAllocatable;
|
|||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
|
||||
use rustc_middle::ty::{self, BoundVar, Const, ToPredicate, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, BoundVar, Const, OpaqueTypeKey, ToPredicate, Ty, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
use std::fmt::Debug;
|
||||
use std::iter;
|
||||
|
@ -90,6 +90,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
var_values: inference_vars,
|
||||
region_constraints: QueryRegionConstraints::default(),
|
||||
certainty: Certainty::Proven, // Ambiguities are OK!
|
||||
opaque_types: vec![],
|
||||
value: answer,
|
||||
})
|
||||
}
|
||||
|
@ -134,14 +135,27 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
let certainty =
|
||||
if ambig_errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous };
|
||||
|
||||
let opaque_types = self.take_opaque_types_for_query_response();
|
||||
|
||||
Ok(QueryResponse {
|
||||
var_values: inference_vars,
|
||||
region_constraints,
|
||||
certainty,
|
||||
value: answer,
|
||||
opaque_types,
|
||||
})
|
||||
}
|
||||
|
||||
fn take_opaque_types_for_query_response(&self) -> Vec<(OpaqueTypeKey<'tcx>, Vec<Ty<'tcx>>)> {
|
||||
self.inner
|
||||
.borrow_mut()
|
||||
.opaque_type_storage
|
||||
.take_opaque_types()
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, v.hidden_types.into_iter().map(|ht| ht.ty).collect()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Given the (canonicalized) result to a canonical query,
|
||||
/// instantiates the result so it can be used, plugging in the
|
||||
/// values from the canonical query. (Note that the result may
|
||||
|
@ -224,13 +238,12 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
where
|
||||
R: Debug + TypeFoldable<'tcx>,
|
||||
{
|
||||
let result_subst =
|
||||
self.query_response_substitution_guess(cause, original_values, query_response);
|
||||
let InferOk { value: result_subst, mut obligations } = self
|
||||
.query_response_substitution_guess(cause, param_env, original_values, query_response)?;
|
||||
|
||||
// Compute `QueryOutlivesConstraint` values that unify each of
|
||||
// the original values `v_o` that was canonicalized into a
|
||||
// variable...
|
||||
let mut obligations = vec![];
|
||||
|
||||
for (index, original_value) in original_values.var_values.iter().enumerate() {
|
||||
// ...with the value `v_r` of that variable from the query.
|
||||
|
@ -345,20 +358,25 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
original_values, query_response,
|
||||
);
|
||||
|
||||
let result_subst =
|
||||
self.query_response_substitution_guess(cause, original_values, query_response);
|
||||
let mut value = self.query_response_substitution_guess(
|
||||
cause,
|
||||
param_env,
|
||||
original_values,
|
||||
query_response,
|
||||
)?;
|
||||
|
||||
let obligations = self
|
||||
.unify_query_response_substitution_guess(
|
||||
value.obligations.extend(
|
||||
self.unify_query_response_substitution_guess(
|
||||
cause,
|
||||
param_env,
|
||||
original_values,
|
||||
&result_subst,
|
||||
&value.value,
|
||||
query_response,
|
||||
)?
|
||||
.into_obligations();
|
||||
.into_obligations(),
|
||||
);
|
||||
|
||||
Ok(InferOk { value: result_subst, obligations })
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
/// Given the original values and the (canonicalized) result from
|
||||
|
@ -373,9 +391,10 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
fn query_response_substitution_guess<R>(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
original_values: &OriginalQueryValues<'tcx>,
|
||||
query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
|
||||
) -> CanonicalVarValues<'tcx>
|
||||
) -> InferResult<'tcx, CanonicalVarValues<'tcx>>
|
||||
where
|
||||
R: Debug + TypeFoldable<'tcx>,
|
||||
{
|
||||
|
@ -475,7 +494,19 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
.collect(),
|
||||
};
|
||||
|
||||
result_subst
|
||||
let mut obligations = vec![];
|
||||
|
||||
// Carry all newly resolved opaque types to the caller's scope
|
||||
for (key, tys) in &query_response.value.opaque_types {
|
||||
let substs = substitute_value(self.tcx, &result_subst, key.substs);
|
||||
let opaque = self.tcx.mk_opaque(key.def_id, substs);
|
||||
for &ty in tys {
|
||||
let ty = substitute_value(self.tcx, &result_subst, ty);
|
||||
obligations.extend(self.handle_opaque_type(opaque, ty, cause, param_env)?);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(InferOk { value: result_subst, obligations })
|
||||
}
|
||||
|
||||
/// Given a "guess" at the values for the canonical variables in
|
||||
|
@ -691,4 +722,14 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
|
|||
fn forbid_inference_vars() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn constrain_opaque_type(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected: bool) {
|
||||
self.obligations.push(self.infcx.opaque_ty_obligation(
|
||||
a,
|
||||
b,
|
||||
a_is_expected,
|
||||
self.param_env,
|
||||
self.cause.clone(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,12 @@ pub struct CombineFields<'infcx, 'tcx> {
|
|||
pub cause: Option<ty::relate::Cause>,
|
||||
pub param_env: ty::ParamEnv<'tcx>,
|
||||
pub obligations: PredicateObligations<'tcx>,
|
||||
/// Whether we should define opaque types
|
||||
/// or just treat them opaquely.
|
||||
/// Currently only used to prevent predicate
|
||||
/// matching from matching anything against opaque
|
||||
/// types.
|
||||
pub define_opaque_types: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
@ -322,6 +328,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
/// will first instantiate `b_vid` with a *generalized* version
|
||||
/// of `a_ty`. Generalization introduces other inference
|
||||
/// variables wherever subtyping could occur.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn instantiate(
|
||||
&mut self,
|
||||
a_ty: Ty<'tcx>,
|
||||
|
@ -334,8 +341,6 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
// Get the actual variable that b_vid has been inferred to
|
||||
debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown());
|
||||
|
||||
debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", a_ty, dir, b_vid);
|
||||
|
||||
// Generalize type of `a_ty` appropriately depending on the
|
||||
// direction. As an example, assume:
|
||||
//
|
||||
|
@ -348,10 +353,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
// variables. (Down below, we will relate `a_ty <: b_ty`,
|
||||
// adding constraints like `'x: '?2` and `?1 <: ?3`.)
|
||||
let Generalization { ty: b_ty, needs_wf } = self.generalize(a_ty, b_vid, dir)?;
|
||||
debug!(
|
||||
"instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})",
|
||||
a_ty, dir, b_vid, b_ty
|
||||
);
|
||||
debug!(?b_ty);
|
||||
self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty);
|
||||
|
||||
if needs_wf {
|
||||
|
@ -392,13 +394,13 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
/// Preconditions:
|
||||
///
|
||||
/// - `for_vid` is a "root vid"
|
||||
#[instrument(skip(self), level = "trace")]
|
||||
fn generalize(
|
||||
&self,
|
||||
ty: Ty<'tcx>,
|
||||
for_vid: ty::TyVid,
|
||||
dir: RelationDir,
|
||||
) -> RelateResult<'tcx, Generalization<'tcx>> {
|
||||
debug!("generalize(ty={:?}, for_vid={:?}, dir={:?}", ty, for_vid, dir);
|
||||
// Determine the ambient variance within which `ty` appears.
|
||||
// The surrounding equation is:
|
||||
//
|
||||
|
@ -412,7 +414,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
RelationDir::SupertypeOf => ty::Contravariant,
|
||||
};
|
||||
|
||||
debug!("generalize: ambient_variance = {:?}", ambient_variance);
|
||||
trace!(?ambient_variance);
|
||||
|
||||
let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) {
|
||||
v @ TypeVariableValue::Known { .. } => {
|
||||
|
@ -421,8 +423,8 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
TypeVariableValue::Unknown { universe } => universe,
|
||||
};
|
||||
|
||||
debug!("generalize: for_universe = {:?}", for_universe);
|
||||
debug!("generalize: trace = {:?}", self.trace);
|
||||
trace!(?for_universe);
|
||||
trace!(?self.trace);
|
||||
|
||||
let mut generalize = Generalizer {
|
||||
infcx: self.infcx,
|
||||
|
@ -439,12 +441,12 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
|
|||
let ty = match generalize.relate(ty, ty) {
|
||||
Ok(ty) => ty,
|
||||
Err(e) => {
|
||||
debug!("generalize: failure {:?}", e);
|
||||
debug!(?e, "failure");
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
let needs_wf = generalize.needs_wf;
|
||||
debug!("generalize: success {{ {:?}, {:?} }}", ty, needs_wf);
|
||||
trace!(?ty, ?needs_wf, "success");
|
||||
Ok(Generalization { ty, needs_wf })
|
||||
}
|
||||
|
||||
|
|
|
@ -75,9 +75,9 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
|
|||
trace!(a = ?a.kind(), b = ?b.kind());
|
||||
|
||||
let infcx = self.fields.infcx;
|
||||
|
||||
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
|
||||
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
|
||||
trace!(a = ?a.kind(), b = ?b.kind(), "replacements");
|
||||
|
||||
match (a.kind(), b.kind()) {
|
||||
(&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => {
|
||||
|
@ -92,6 +92,21 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
|
|||
self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?;
|
||||
}
|
||||
|
||||
(&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
|
||||
self.fields.infcx.super_combine_tys(self, a, b)?;
|
||||
}
|
||||
(&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
|
||||
if self.fields.define_opaque_types && did.is_local() =>
|
||||
{
|
||||
self.fields.obligations.push(infcx.opaque_ty_obligation(
|
||||
a,
|
||||
b,
|
||||
self.a_is_expected(),
|
||||
self.param_env(),
|
||||
self.fields.trace.cause.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
_ => {
|
||||
self.fields.infcx.super_combine_tys(self, a, b)?;
|
||||
}
|
||||
|
|
|
@ -214,8 +214,8 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
|
|||
| ty::Foreign(..)
|
||||
| ty::Param(..)
|
||||
| ty::Closure(..)
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::Opaque(..) => t.super_fold_with(self),
|
||||
| ty::Opaque(..)
|
||||
| ty::GeneratorWitness(..) => t.super_fold_with(self),
|
||||
|
||||
ty::Placeholder(..) | ty::Bound(..) => bug!("unexpected type {:?}", t),
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use super::InferCtxt;
|
|||
use super::Subtype;
|
||||
|
||||
use crate::infer::combine::ConstEquateRelation;
|
||||
use crate::traits::ObligationCause;
|
||||
use crate::traits::{ObligationCause, PredicateObligation};
|
||||
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
||||
|
@ -111,12 +111,20 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
|
|||
&self.fields.trace.cause
|
||||
}
|
||||
|
||||
fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>) {
|
||||
self.fields.obligations.extend(obligations)
|
||||
}
|
||||
|
||||
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
|
||||
let mut sub = self.fields.sub(self.a_is_expected);
|
||||
sub.relate(v, a)?;
|
||||
sub.relate(v, b)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn define_opaque_types(&self) -> bool {
|
||||
self.fields.define_opaque_types
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ConstEquateRelation<'tcx> for Glb<'_, '_, 'tcx> {
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use super::InferCtxt;
|
||||
|
||||
use crate::traits::ObligationCause;
|
||||
use crate::traits::{ObligationCause, PredicateObligation};
|
||||
use rustc_middle::ty::relate::{RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::TyVar;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
|
@ -32,6 +32,10 @@ pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> {
|
|||
|
||||
fn cause(&self) -> &ObligationCause<'tcx>;
|
||||
|
||||
fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>);
|
||||
|
||||
fn define_opaque_types(&self) -> bool;
|
||||
|
||||
// Relates the type `v` to `a` and `b` such that `v` represents
|
||||
// the LUB/GLB of `a` and `b` as appropriate.
|
||||
//
|
||||
|
@ -41,6 +45,7 @@ pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> {
|
|||
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
|
||||
}
|
||||
|
||||
#[instrument(skip(this), level = "debug")]
|
||||
pub fn super_lattice_tys<'a, 'tcx: 'a, L>(
|
||||
this: &mut L,
|
||||
a: Ty<'tcx>,
|
||||
|
@ -49,15 +54,17 @@ pub fn super_lattice_tys<'a, 'tcx: 'a, L>(
|
|||
where
|
||||
L: LatticeDir<'a, 'tcx>,
|
||||
{
|
||||
debug!("{}.lattice_tys({:?}, {:?})", this.tag(), a, b);
|
||||
debug!("{}", this.tag());
|
||||
|
||||
if a == b {
|
||||
return Ok(a);
|
||||
}
|
||||
|
||||
let infcx = this.infcx();
|
||||
|
||||
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
|
||||
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
|
||||
|
||||
match (a.kind(), b.kind()) {
|
||||
// If one side is known to be a variable and one is not,
|
||||
// create a variable (`v`) to represent the LUB. Make sure to
|
||||
|
@ -94,6 +101,22 @@ where
|
|||
Ok(v)
|
||||
}
|
||||
|
||||
(&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
|
||||
infcx.super_combine_tys(this, a, b)
|
||||
}
|
||||
(&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
|
||||
if this.define_opaque_types() && did.is_local() =>
|
||||
{
|
||||
this.add_obligations(vec![infcx.opaque_ty_obligation(
|
||||
a,
|
||||
b,
|
||||
this.a_is_expected(),
|
||||
this.param_env(),
|
||||
this.cause().clone(),
|
||||
)]);
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
_ => infcx.super_combine_tys(this, a, b),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use super::InferCtxt;
|
|||
use super::Subtype;
|
||||
|
||||
use crate::infer::combine::ConstEquateRelation;
|
||||
use crate::traits::ObligationCause;
|
||||
use crate::traits::{ObligationCause, PredicateObligation};
|
||||
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
||||
|
@ -117,10 +117,18 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
|
|||
&self.fields.trace.cause
|
||||
}
|
||||
|
||||
fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>) {
|
||||
self.fields.obligations.extend(obligations)
|
||||
}
|
||||
|
||||
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
|
||||
let mut sub = self.fields.sub(self.a_is_expected);
|
||||
sub.relate(a, v)?;
|
||||
sub.relate(b, v)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn define_opaque_types(&self) -> bool {
|
||||
self.fields.define_opaque_types
|
||||
}
|
||||
}
|
||||
|
|
|
@ -227,7 +227,7 @@ impl<'tcx> InferCtxtInner<'tcx> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> {
|
||||
pub fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> {
|
||||
self.opaque_type_storage.with_log(&mut self.undo_log)
|
||||
}
|
||||
|
||||
|
@ -291,6 +291,10 @@ pub struct InferCtxt<'a, 'tcx> {
|
|||
/// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
|
||||
pub defining_use_anchor: Option<LocalDefId>,
|
||||
|
||||
/// Used by WF-checking to not have to figure out hidden types itself, but
|
||||
/// to just invoke type_of to get the already computed hidden type from typeck.
|
||||
pub reveal_defining_opaque_types: bool,
|
||||
|
||||
/// During type-checking/inference of a body, `in_progress_typeck_results`
|
||||
/// contains a reference to the typeck results being built up, which are
|
||||
/// used for reading closure kinds/signatures as they are inferred,
|
||||
|
@ -546,6 +550,7 @@ pub struct InferCtxtBuilder<'tcx> {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
|
||||
defining_use_anchor: Option<LocalDefId>,
|
||||
reveal_defining_opaque_types: bool,
|
||||
}
|
||||
|
||||
pub trait TyCtxtInferExt<'tcx> {
|
||||
|
@ -554,7 +559,12 @@ pub trait TyCtxtInferExt<'tcx> {
|
|||
|
||||
impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
|
||||
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
|
||||
InferCtxtBuilder { tcx: self, defining_use_anchor: None, fresh_typeck_results: None }
|
||||
InferCtxtBuilder {
|
||||
tcx: self,
|
||||
defining_use_anchor: None,
|
||||
fresh_typeck_results: None,
|
||||
reveal_defining_opaque_types: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -578,6 +588,13 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
|||
self
|
||||
}
|
||||
|
||||
/// WF-checking doesn't need to recompute opaque types and can instead use
|
||||
/// the type_of query to get them from typeck.
|
||||
pub fn reveal_defining_opaque_types(mut self) -> Self {
|
||||
self.reveal_defining_opaque_types = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Given a canonical value `C` as a starting point, create an
|
||||
/// inference context that contains each of the bound values
|
||||
/// within instantiated as a fresh variable. The `f` closure is
|
||||
|
@ -602,11 +619,17 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
|||
}
|
||||
|
||||
pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
|
||||
let InferCtxtBuilder { tcx, defining_use_anchor, ref fresh_typeck_results } = *self;
|
||||
let InferCtxtBuilder {
|
||||
tcx,
|
||||
defining_use_anchor,
|
||||
reveal_defining_opaque_types,
|
||||
ref fresh_typeck_results,
|
||||
} = *self;
|
||||
let in_progress_typeck_results = fresh_typeck_results.as_ref();
|
||||
f(InferCtxt {
|
||||
tcx,
|
||||
defining_use_anchor,
|
||||
reveal_defining_opaque_types,
|
||||
in_progress_typeck_results,
|
||||
inner: RefCell::new(InferCtxtInner::new()),
|
||||
lexical_region_resolutions: RefCell::new(None),
|
||||
|
@ -728,6 +751,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
&'a self,
|
||||
trace: TypeTrace<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
define_opaque_types: bool,
|
||||
) -> CombineFields<'a, 'tcx> {
|
||||
CombineFields {
|
||||
infcx: self,
|
||||
|
@ -735,6 +759,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
cause: None,
|
||||
param_env,
|
||||
obligations: PredicateObligations::new(),
|
||||
define_opaque_types,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1050,12 +1075,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
self.tcx.mk_ty_var(self.next_ty_var_id(origin))
|
||||
}
|
||||
|
||||
pub fn next_ty_var_id_in_universe(
|
||||
&self,
|
||||
origin: TypeVariableOrigin,
|
||||
universe: ty::UniverseIndex,
|
||||
) -> TyVid {
|
||||
self.inner.borrow_mut().type_variables().new_var(universe, origin)
|
||||
}
|
||||
|
||||
pub fn next_ty_var_in_universe(
|
||||
&self,
|
||||
origin: TypeVariableOrigin,
|
||||
universe: ty::UniverseIndex,
|
||||
) -> Ty<'tcx> {
|
||||
let vid = self.inner.borrow_mut().type_variables().new_var(universe, origin);
|
||||
let vid = self.next_ty_var_id_in_universe(origin, universe);
|
||||
self.tcx.mk_ty_var(vid)
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
use crate::infer::combine::ConstEquateRelation;
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::infer::{ConstVarValue, ConstVariableValue};
|
||||
use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor};
|
||||
|
@ -89,6 +90,8 @@ pub trait TypeRelatingDelegate<'tcx> {
|
|||
info: ty::VarianceDiagInfo<'tcx>,
|
||||
);
|
||||
|
||||
fn constrain_opaque_type(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected: bool);
|
||||
|
||||
fn const_equate(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>);
|
||||
|
||||
/// Creates a new universe index. Used when instantiating placeholders.
|
||||
|
@ -279,7 +282,6 @@ where
|
|||
projection_ty: ty::ProjectionTy<'tcx>,
|
||||
value_ty: Ty<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
match *value_ty.kind() {
|
||||
|
@ -288,6 +290,8 @@ where
|
|||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
span: DUMMY_SP,
|
||||
});
|
||||
// FIXME(lazy-normalization): This will always ICE, because the recursive
|
||||
// call will end up in the _ arm below.
|
||||
self.relate_projection_ty(projection_ty, var);
|
||||
self.relate_projection_ty(other_projection_ty, var);
|
||||
var
|
||||
|
@ -533,6 +537,8 @@ where
|
|||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
let infcx = self.infcx;
|
||||
|
||||
let a = self.infcx.shallow_resolve(a);
|
||||
|
||||
if !D::forbid_inference_vars() {
|
||||
|
@ -561,6 +567,35 @@ where
|
|||
|
||||
(&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)),
|
||||
|
||||
(&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
|
||||
self.infcx.super_combine_tys(self, a, b)
|
||||
}
|
||||
(&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..)) if did.is_local() => {
|
||||
let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
|
||||
let mut generalize = |ty, ty_is_expected| {
|
||||
let var = infcx.next_ty_var_id_in_universe(
|
||||
TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
span: self.delegate.span(),
|
||||
},
|
||||
ty::UniverseIndex::ROOT,
|
||||
);
|
||||
if ty_is_expected {
|
||||
self.relate_ty_var((ty, var))
|
||||
} else {
|
||||
self.relate_ty_var((var, ty))
|
||||
}
|
||||
};
|
||||
let (a, b) = match (a.kind(), b.kind()) {
|
||||
(&ty::Opaque(..), _) => (a, generalize(b, false)?),
|
||||
(_, &ty::Opaque(..)) => (generalize(a, true)?, b),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.delegate.constrain_opaque_type(a, b, true);
|
||||
trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
(&ty::Projection(projection_ty), _)
|
||||
if D::normalization() == NormalizationStrategy::Lazy =>
|
||||
{
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::infer::{InferCtxt, InferOk};
|
||||
use crate::traits;
|
||||
use crate::infer::{InferCtxt, InferOk, InferResult};
|
||||
use crate::traits::{self, PredicateObligation, PredicateObligations};
|
||||
use hir::def_id::{DefId, LocalDefId};
|
||||
use hir::OpaqueTyOrigin;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::vec_map::VecMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::fold::BottomUpFolder;
|
||||
use rustc_middle::ty::subst::{GenericArgKind, Subst};
|
||||
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitor};
|
||||
|
@ -21,11 +24,71 @@ pub use table::{OpaqueTypeStorage, OpaqueTypeTable};
|
|||
/// Information about the opaque types whose values we
|
||||
/// are inferring in this function (these are the `impl Trait` that
|
||||
/// appear in the return type).
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OpaqueTypeDecl<'tcx> {
|
||||
/// The opaque type (`ty::Opaque`) for this declaration.
|
||||
pub opaque_type: Ty<'tcx>,
|
||||
|
||||
/// The hidden types that have been inferred for this opaque type.
|
||||
/// There can be multiple, but they are all `lub`ed together at the end
|
||||
/// to obtain the canonical hidden type.
|
||||
pub hidden_types: Vec<OpaqueHiddenType<'tcx>>,
|
||||
|
||||
/// The origin of the opaque type.
|
||||
pub origin: hir::OpaqueTyOrigin,
|
||||
}
|
||||
|
||||
impl<'tcx> OpaqueTypeDecl<'tcx> {
|
||||
pub fn hidden_type(
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Result<
|
||||
InferOk<'tcx, OpaqueHiddenType<'tcx>>,
|
||||
(TypeError<'tcx>, OpaqueHiddenType<'tcx>, OpaqueHiddenType<'tcx>),
|
||||
> {
|
||||
let mut value = self.hidden_types[0];
|
||||
let mut obligations = vec![];
|
||||
let mut error: Option<(_, _, OpaqueHiddenType<'tcx>)> = None;
|
||||
for &next in self.hidden_types[1..].iter() {
|
||||
// FIXME: make use of the spans to get nicer diagnostics!
|
||||
let res = match infcx.at(cause, param_env).eq(value.ty, next.ty) {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
// Try to improve the span. Sometimes we have dummy spans, sometimes we are pointing
|
||||
// at an if/match instead of at the arm that gave us the type, but later spans point
|
||||
// to the right thing.
|
||||
if let Some((_, _, old)) = &mut error {
|
||||
old.span = old.span.substitute_dummy(next.span);
|
||||
// Shrink the span if possible
|
||||
if old.span.contains(next.span) {
|
||||
old.span = next.span;
|
||||
}
|
||||
} else {
|
||||
let mut next = next;
|
||||
next.span = next.span.substitute_dummy(cause.span(infcx.tcx));
|
||||
error = Some((e, value, next));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
};
|
||||
obligations.extend(res.obligations);
|
||||
value.span = value.span.substitute_dummy(next.span);
|
||||
// Shrink the span if possible
|
||||
if value.span.contains(next.span) {
|
||||
value.span = next.span;
|
||||
}
|
||||
}
|
||||
match error {
|
||||
None => Ok(InferOk { value, obligations }),
|
||||
Some(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, TypeFoldable)]
|
||||
pub struct OpaqueHiddenType<'tcx> {
|
||||
/// The span of this particular definition of the opaque type. So
|
||||
/// for example:
|
||||
///
|
||||
|
@ -39,7 +102,7 @@ pub struct OpaqueTypeDecl<'tcx> {
|
|||
/// In cases where the fn returns `(impl Trait, impl Trait)` or
|
||||
/// other such combinations, the result is currently
|
||||
/// over-approximated, but better than nothing.
|
||||
pub definition_span: Span,
|
||||
pub span: Span,
|
||||
|
||||
/// The type variable that represents the value of the opaque type
|
||||
/// that we require. In other words, after we compile this function,
|
||||
|
@ -53,22 +116,21 @@ pub struct OpaqueTypeDecl<'tcx> {
|
|||
/// those that are arguments to `Foo` in the constraint above. (In
|
||||
/// other words, `?C` should not include `'b`, even though it's a
|
||||
/// lifetime parameter on `foo`.)
|
||||
pub concrete_ty: Ty<'tcx>,
|
||||
|
||||
/// The origin of the opaque type.
|
||||
pub origin: hir::OpaqueTyOrigin,
|
||||
pub ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
/// Replaces all opaque types in `value` with fresh inference variables
|
||||
/// Links the opaque type with the given hidden type
|
||||
/// and creates appropriate obligations. For example, given the input:
|
||||
///
|
||||
/// impl Iterator<Item = impl Debug>
|
||||
/// opaque = impl Iterator<Item = impl Debug>
|
||||
/// hidden = std::vec::IntoIter<i32>
|
||||
///
|
||||
/// this method would create two type variables, `?0` and `?1`. It would
|
||||
/// return the type `?0` but also the obligations:
|
||||
/// this method would register the opaque type `impl Iterator` to have
|
||||
/// the hidden type `std::vec::IntoIter<i32>` and create the type variable
|
||||
/// `?1` but also the obligations:
|
||||
///
|
||||
/// ?0: Iterator<Item = ?1>
|
||||
/// std::vec::IntoIter<i32>: Iterator<Item = ?1>
|
||||
/// ?1: Debug
|
||||
///
|
||||
/// Moreover, it returns an `OpaqueTypeMap` that would map `?0` to
|
||||
|
@ -85,22 +147,73 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
/// obligations
|
||||
/// - `value` -- the value within which we are instantiating opaque types
|
||||
/// - `value_span` -- the span where the value came from, used in error reporting
|
||||
pub fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
|
||||
pub fn instantiate_opaque_types(
|
||||
&self,
|
||||
body_id: hir::HirId,
|
||||
ty: Ty<'tcx>,
|
||||
opaque: Ty<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
value: T,
|
||||
value_span: Span,
|
||||
) -> InferOk<'tcx, T> {
|
||||
debug!(
|
||||
"instantiate_opaque_types(value={:?}, body_id={:?}, \
|
||||
param_env={:?}, value_span={:?})",
|
||||
value, body_id, param_env, value_span,
|
||||
);
|
||||
let mut instantiator =
|
||||
Instantiator { infcx: self, body_id, param_env, value_span, obligations: vec![] };
|
||||
let value = instantiator.instantiate_opaque_types_in_map(value);
|
||||
InferOk { value, obligations: instantiator.obligations }
|
||||
) -> Option<InferOk<'tcx, Ty<'tcx>>> {
|
||||
let mut obligations = vec![];
|
||||
let value = Instantiator { infcx: self, cause, param_env, obligations: &mut obligations }
|
||||
.fold_opaque_ty_new(opaque, |_, _| ty)?;
|
||||
Some(InferOk { value, obligations })
|
||||
}
|
||||
|
||||
pub fn handle_opaque_type(
|
||||
&self,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Result<PredicateObligations<'tcx>, TypeError<'tcx>> {
|
||||
if a.references_error() || b.references_error() {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
if self.defining_use_anchor.is_some() {
|
||||
let process = |a: Ty<'tcx>, b: Ty<'tcx>| {
|
||||
if !matches!(a.kind(), ty::Opaque(..)) {
|
||||
return None;
|
||||
}
|
||||
self.instantiate_opaque_types(b, a, cause.clone(), param_env)
|
||||
.map(|res| res.obligations)
|
||||
};
|
||||
if let Some(res) = process(a, b) {
|
||||
Ok(res)
|
||||
} else if let Some(res) = process(b, a) {
|
||||
Ok(res)
|
||||
} else {
|
||||
// Rerun equality check, but this time error out due to
|
||||
// different types.
|
||||
match self.at(cause, param_env).define_opaque_types(false).eq(a, b) {
|
||||
Ok(_) => span_bug!(
|
||||
cause.span,
|
||||
"opaque types are never equal to anything but themselves: {:#?}",
|
||||
(a, b)
|
||||
),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let (opaque_type, hidden_ty) = match (a.kind(), b.kind()) {
|
||||
(ty::Opaque(..), _) => (a, b),
|
||||
(_, ty::Opaque(..)) => (b, a),
|
||||
types => span_bug!(
|
||||
cause.span,
|
||||
"opaque type obligations only work for opaque types: {:#?}",
|
||||
types
|
||||
),
|
||||
};
|
||||
let key = opaque_type.expect_opaque_type();
|
||||
let origin = self.opaque_ty_origin_unchecked(key.def_id, cause.span);
|
||||
self.inner.borrow_mut().opaque_types().register(
|
||||
key,
|
||||
opaque_type,
|
||||
OpaqueHiddenType { ty: hidden_ty, span: cause.span },
|
||||
origin,
|
||||
);
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
/// Given the map `opaque_types` containing the opaque
|
||||
|
@ -268,18 +381,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
#[instrument(level = "debug", skip(self))]
|
||||
pub fn constrain_opaque_type(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
opaque_defn: &OpaqueTypeDecl<'tcx>,
|
||||
) {
|
||||
concrete_ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> InferResult<'tcx, ()> {
|
||||
let def_id = opaque_type_key.def_id;
|
||||
|
||||
let tcx = self.tcx;
|
||||
|
||||
let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty);
|
||||
let concrete_ty = self.resolve_vars_if_possible(concrete_ty);
|
||||
|
||||
debug!(?concrete_ty);
|
||||
|
||||
let first_own_region = match opaque_defn.origin {
|
||||
let first_own_region = match self.opaque_ty_origin_unchecked(def_id, span) {
|
||||
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {
|
||||
// We lower
|
||||
//
|
||||
|
@ -323,24 +438,44 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
op: |r| {
|
||||
self.member_constraint(
|
||||
opaque_type_key.def_id,
|
||||
opaque_defn.definition_span,
|
||||
span,
|
||||
concrete_ty,
|
||||
r,
|
||||
&choice_regions,
|
||||
)
|
||||
},
|
||||
});
|
||||
Ok(InferOk { value: (), obligations: vec![] })
|
||||
}
|
||||
|
||||
fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<hir::OpaqueTyOrigin> {
|
||||
let tcx = self.tcx;
|
||||
let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
pub fn opaque_ty_obligation(
|
||||
&self,
|
||||
a: Ty<'tcx>,
|
||||
b: Ty<'tcx>,
|
||||
a_is_expected: bool,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
) -> PredicateObligation<'tcx> {
|
||||
let (a, b) = if a_is_expected { (a, b) } else { (b, a) };
|
||||
PredicateObligation::new(
|
||||
cause,
|
||||
param_env,
|
||||
self.tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::OpaqueType(a, b))),
|
||||
)
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "trace")]
|
||||
pub fn opaque_type_origin(&self, opaque_def_id: DefId, span: Span) -> Option<OpaqueTyOrigin> {
|
||||
let def_id = opaque_def_id.as_local()?;
|
||||
let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let parent_def_id = self.defining_use_anchor?;
|
||||
let item_kind = &tcx.hir().expect_item(def_id).kind;
|
||||
let item_kind = &self.tcx.hir().expect_item(def_id).kind;
|
||||
|
||||
let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else {
|
||||
span_bug!(
|
||||
tcx.def_span(def_id),
|
||||
"weird opaque type: {:#?}",
|
||||
span,
|
||||
"weird opaque type: {:#?}, {:#?}",
|
||||
opaque_def_id,
|
||||
item_kind
|
||||
)
|
||||
};
|
||||
|
@ -351,12 +486,26 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
|
||||
// Named `type Foo = impl Bar;`
|
||||
hir::OpaqueTyOrigin::TyAlias => {
|
||||
may_define_opaque_type(tcx, parent_def_id, opaque_hir_id)
|
||||
may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
|
||||
}
|
||||
};
|
||||
trace!(?origin);
|
||||
in_definition_scope.then_some(*origin)
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "trace")]
|
||||
fn opaque_ty_origin_unchecked(&self, opaque_def_id: DefId, span: Span) -> OpaqueTyOrigin {
|
||||
let def_id = opaque_def_id.as_local().unwrap();
|
||||
let origin = match self.tcx.hir().expect_item(def_id).kind {
|
||||
hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin,
|
||||
ref itemkind => {
|
||||
span_bug!(span, "weird opaque type: {:?}, {:#?}", opaque_def_id, itemkind)
|
||||
}
|
||||
};
|
||||
trace!(?origin);
|
||||
origin
|
||||
}
|
||||
|
||||
pub fn opaque_types(&self) -> OpaqueTypeMap<'tcx> {
|
||||
self.inner.borrow().opaque_type_storage.opaque_types()
|
||||
}
|
||||
|
@ -434,177 +583,166 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub enum UseKind {
|
||||
DefiningUse,
|
||||
OpaqueUse,
|
||||
}
|
||||
|
||||
impl UseKind {
|
||||
pub fn is_defining(self) -> bool {
|
||||
match self {
|
||||
UseKind::DefiningUse => true,
|
||||
UseKind::OpaqueUse => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Instantiator<'a, 'tcx> {
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
body_id: hir::HirId,
|
||||
cause: ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
value_span: Span,
|
||||
obligations: Vec<traits::PredicateObligation<'tcx>>,
|
||||
obligations: &'a mut PredicateObligations<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Instantiator<'a, 'tcx> {
|
||||
fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
|
||||
let tcx = self.infcx.tcx;
|
||||
value.fold_with(&mut BottomUpFolder {
|
||||
tcx,
|
||||
ty_op: |ty| {
|
||||
if ty.references_error() {
|
||||
return tcx.ty_error();
|
||||
} else if let ty::Opaque(def_id, substs) = ty.kind() {
|
||||
// Check that this is `impl Trait` type is
|
||||
// declared by `parent_def_id` -- i.e., one whose
|
||||
// value we are inferring. At present, this is
|
||||
// always true during the first phase of
|
||||
// type-check, but not always true later on during
|
||||
// NLL. Once we support named opaque types more fully,
|
||||
// this same scenario will be able to arise during all phases.
|
||||
//
|
||||
// Here is an example using type alias `impl Trait`
|
||||
// that indicates the distinction we are checking for:
|
||||
//
|
||||
// ```rust
|
||||
// mod a {
|
||||
// pub type Foo = impl Iterator;
|
||||
// pub fn make_foo() -> Foo { .. }
|
||||
// }
|
||||
//
|
||||
// mod b {
|
||||
// fn foo() -> a::Foo { a::make_foo() }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// Here, the return type of `foo` references an
|
||||
// `Opaque` indeed, but not one whose value is
|
||||
// presently being inferred. You can get into a
|
||||
// similar situation with closure return types
|
||||
// today:
|
||||
//
|
||||
// ```rust
|
||||
// fn foo() -> impl Iterator { .. }
|
||||
// fn bar() {
|
||||
// let x = || foo(); // returns the Opaque assoc with `foo`
|
||||
// }
|
||||
// ```
|
||||
if let Some(def_id) = def_id.as_local() {
|
||||
if let Some(origin) = self.infcx.opaque_type_origin(def_id) {
|
||||
let opaque_type_key =
|
||||
OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
|
||||
return self.fold_opaque_ty(ty, opaque_type_key, origin);
|
||||
}
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn instantiate_opaque_types(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
if let Some(ty) = self.fold_opaque_ty_new(ty, |infcx, span| {
|
||||
infcx.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::TypeInference,
|
||||
span,
|
||||
})
|
||||
}) {
|
||||
return ty;
|
||||
}
|
||||
|
||||
debug!(
|
||||
"instantiate_opaque_types_in_map: \
|
||||
encountered opaque outside its definition scope \
|
||||
def_id={:?}",
|
||||
def_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ty
|
||||
},
|
||||
lt_op: |lt| lt,
|
||||
ct_op: |ct| ct,
|
||||
})
|
||||
ty
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn fold_opaque_ty_new(
|
||||
&mut self,
|
||||
ty: Ty<'tcx>,
|
||||
mk_ty: impl FnOnce(&InferCtxt<'_, 'tcx>, Span) -> Ty<'tcx>,
|
||||
) -> Option<Ty<'tcx>> {
|
||||
// Check that this is `impl Trait` type is
|
||||
// declared by `parent_def_id` -- i.e., one whose
|
||||
// value we are inferring. At present, this is
|
||||
// always true during the first phase of
|
||||
// type-check, but not always true later on during
|
||||
// NLL. Once we support named opaque types more fully,
|
||||
// this same scenario will be able to arise during all phases.
|
||||
//
|
||||
// Here is an example using type alias `impl Trait`
|
||||
// that indicates the distinction we are checking for:
|
||||
//
|
||||
// ```rust
|
||||
// mod a {
|
||||
// pub type Foo = impl Iterator;
|
||||
// pub fn make_foo() -> Foo { .. }
|
||||
// }
|
||||
//
|
||||
// mod b {
|
||||
// fn foo() -> a::Foo { a::make_foo() }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// Here, the return type of `foo` references an
|
||||
// `Opaque` indeed, but not one whose value is
|
||||
// presently being inferred. You can get into a
|
||||
// similar situation with closure return types
|
||||
// today:
|
||||
//
|
||||
// ```rust
|
||||
// fn foo() -> impl Iterator { .. }
|
||||
// fn bar() {
|
||||
// let x = || foo(); // returns the Opaque assoc with `foo`
|
||||
// }
|
||||
// ```
|
||||
let opaque_type_key = ty.expect_opaque_type();
|
||||
if let Some(origin) = self.infcx.opaque_type_origin(opaque_type_key.def_id, self.cause.span)
|
||||
{
|
||||
return Some(self.fold_opaque_ty(ty, opaque_type_key, origin, mk_ty));
|
||||
}
|
||||
|
||||
debug!(?ty, "encountered opaque outside its definition scope",);
|
||||
None
|
||||
}
|
||||
|
||||
#[instrument(skip(self, mk_ty), level = "debug")]
|
||||
fn fold_opaque_ty(
|
||||
&mut self,
|
||||
ty: Ty<'tcx>,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
origin: hir::OpaqueTyOrigin,
|
||||
mk_ty: impl FnOnce(&InferCtxt<'_, 'tcx>, Span) -> Ty<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let infcx = self.infcx;
|
||||
let tcx = infcx.tcx;
|
||||
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
|
||||
|
||||
// Use the same type variable if the exact same opaque type appears more
|
||||
// than once in the return type (e.g., if it's passed to a type alias).
|
||||
if let Some(opaque_defn) =
|
||||
infcx.inner.borrow().opaque_type_storage.get_decl(&opaque_type_key)
|
||||
{
|
||||
debug!("re-using cached concrete type {:?}", opaque_defn.concrete_ty.kind());
|
||||
return opaque_defn.concrete_ty;
|
||||
}
|
||||
|
||||
let ty_var = infcx.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::TypeInference,
|
||||
span: self.value_span,
|
||||
});
|
||||
let ty_var = mk_ty(infcx, self.cause.span);
|
||||
|
||||
// Ideally, we'd get the span where *this specific `ty` came
|
||||
// from*, but right now we just use the span from the overall
|
||||
// value being folded. In simple cases like `-> impl Foo`,
|
||||
// these are the same span, but not in cases like `-> (impl
|
||||
// Foo, impl Bar)`.
|
||||
let definition_span = self.value_span;
|
||||
let span = self.cause.span;
|
||||
|
||||
self.infcx.inner.borrow_mut().opaque_types().register(
|
||||
OpaqueTypeKey { def_id, substs },
|
||||
OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin },
|
||||
ty,
|
||||
OpaqueHiddenType { ty: ty_var, span },
|
||||
origin,
|
||||
);
|
||||
|
||||
debug!("generated new type inference var {:?}", ty_var.kind());
|
||||
|
||||
let item_bounds = tcx.explicit_item_bounds(def_id);
|
||||
|
||||
self.obligations.reserve(item_bounds.len());
|
||||
for (predicate, _) in item_bounds {
|
||||
debug!(?predicate);
|
||||
let predicate = predicate.subst(tcx, substs);
|
||||
debug!(?predicate);
|
||||
|
||||
let predicate = predicate.fold_with(&mut BottomUpFolder {
|
||||
tcx,
|
||||
ty_op: |ty| match *ty.kind() {
|
||||
// We can't normalize associated types from `rustc_infer`,
|
||||
// but we can eagerly register inference variables for them.
|
||||
ty::Projection(projection_ty) if !projection_ty.has_escaping_bound_vars() => infcx.infer_projection(
|
||||
self.param_env,
|
||||
projection_ty,
|
||||
self.cause.clone(),
|
||||
0,
|
||||
&mut self.obligations,
|
||||
),
|
||||
// Replace all other mentions of the same opaque type with the hidden type,
|
||||
// as the bounds must hold on the hidden type after all.
|
||||
ty::Opaque(def_id2, substs2) if def_id == def_id2 && substs == substs2 => {
|
||||
ty_var
|
||||
}
|
||||
// Instantiate nested instances of `impl Trait`.
|
||||
ty::Opaque(..) => self.instantiate_opaque_types_in_map(ty),
|
||||
ty::Opaque(..) => self.instantiate_opaque_types(ty),
|
||||
_ => ty,
|
||||
},
|
||||
lt_op: |lt| lt,
|
||||
ct_op: |ct| ct,
|
||||
});
|
||||
|
||||
// We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them.
|
||||
let predicate = predicate.fold_with(&mut BottomUpFolder {
|
||||
tcx,
|
||||
ty_op: |ty| match ty.kind() {
|
||||
ty::Projection(projection_ty) if !projection_ty.has_escaping_bound_vars() => {
|
||||
infcx.infer_projection(
|
||||
self.param_env,
|
||||
*projection_ty,
|
||||
traits::ObligationCause::misc(self.value_span, self.body_id),
|
||||
0,
|
||||
&mut self.obligations,
|
||||
)
|
||||
}
|
||||
_ => ty,
|
||||
},
|
||||
lt_op: |lt| lt,
|
||||
ct_op: |ct| ct,
|
||||
});
|
||||
debug!(?predicate);
|
||||
|
||||
if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
|
||||
if projection.term.references_error() {
|
||||
// No point on adding these obligations since there's a type error involved.
|
||||
return tcx.ty_error();
|
||||
}
|
||||
trace!("{:#?}", projection.term);
|
||||
}
|
||||
|
||||
let cause =
|
||||
traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType);
|
||||
|
||||
// Require that the predicate holds for the concrete type.
|
||||
debug!(?predicate);
|
||||
self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
|
||||
self.obligations.push(traits::Obligation::new(
|
||||
self.cause.clone(),
|
||||
self.param_env,
|
||||
predicate,
|
||||
));
|
||||
}
|
||||
|
||||
ty_var
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::undo_log::UndoLogs;
|
||||
use rustc_hir::OpaqueTyOrigin;
|
||||
use rustc_middle::ty::{self, OpaqueTypeKey, Ty};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
||||
use crate::infer::InferCtxtUndoLogs;
|
||||
use crate::infer::{InferCtxtUndoLogs, UndoLog};
|
||||
|
||||
use super::{OpaqueTypeDecl, OpaqueTypeMap};
|
||||
use super::{OpaqueHiddenType, OpaqueTypeDecl, OpaqueTypeMap};
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct OpaqueTypeStorage<'tcx> {
|
||||
|
@ -14,21 +14,18 @@ pub struct OpaqueTypeStorage<'tcx> {
|
|||
// variables to get the concrete type, which can be used to
|
||||
// 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
|
||||
pub opaque_types: OpaqueTypeMap<'tcx>,
|
||||
|
||||
/// A map from inference variables created from opaque
|
||||
/// type instantiations (`ty::Infer`) to the actual opaque
|
||||
/// type (`ty::Opaque`). Used during fallback to map unconstrained
|
||||
/// opaque type inference variables to their corresponding
|
||||
/// opaque type.
|
||||
pub opaque_types_vars: FxHashMap<Ty<'tcx>, Ty<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> OpaqueTypeStorage<'tcx> {
|
||||
#[instrument(level = "debug")]
|
||||
pub(crate) fn remove(&mut self, key: OpaqueTypeKey<'tcx>) {
|
||||
match self.opaque_types.remove(&key) {
|
||||
None => bug!("reverted opaque type inference that was never registered"),
|
||||
Some(decl) => assert_ne!(self.opaque_types_vars.remove(decl.concrete_ty), None),
|
||||
pub(crate) fn remove(&mut self, key: OpaqueTypeKey<'tcx>, idx: usize) {
|
||||
if idx == 0 {
|
||||
match self.opaque_types.remove(&key) {
|
||||
None => bug!("reverted opaque type inference that was never registered: {:?}", key),
|
||||
Some(_) => {}
|
||||
}
|
||||
} else {
|
||||
self.opaque_types.get_mut(&key).unwrap().hidden_types.drain(idx..);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,10 +33,6 @@ impl<'tcx> OpaqueTypeStorage<'tcx> {
|
|||
self.opaque_types.get(key)
|
||||
}
|
||||
|
||||
pub fn get_opaque_type_for_infer_var(&self, key: Ty<'tcx>) -> Option<Ty<'tcx>> {
|
||||
self.opaque_types_vars.get(key).copied()
|
||||
}
|
||||
|
||||
pub fn opaque_types(&self) -> OpaqueTypeMap<'tcx> {
|
||||
self.opaque_types.clone()
|
||||
}
|
||||
|
@ -76,9 +69,20 @@ pub struct OpaqueTypeTable<'a, 'tcx> {
|
|||
|
||||
impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> {
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub fn register(&mut self, key: OpaqueTypeKey<'tcx>, decl: OpaqueTypeDecl<'tcx>) {
|
||||
self.undo_log.push(key);
|
||||
pub fn register(
|
||||
&mut self,
|
||||
key: OpaqueTypeKey<'tcx>,
|
||||
opaque_type: Ty<'tcx>,
|
||||
ty: OpaqueHiddenType<'tcx>,
|
||||
origin: OpaqueTyOrigin,
|
||||
) {
|
||||
if let Some(decl) = self.storage.opaque_types.get_mut(&key) {
|
||||
decl.hidden_types.push(ty);
|
||||
self.undo_log.push(UndoLog::OpaqueTypes(key, decl.hidden_types.len()));
|
||||
return;
|
||||
}
|
||||
let decl = OpaqueTypeDecl { opaque_type, hidden_types: vec![ty], origin };
|
||||
self.storage.opaque_types.insert(key, decl);
|
||||
self.storage.opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type);
|
||||
self.undo_log.push(UndoLog::OpaqueTypes(key, 0));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ pub fn explicit_outlives_bounds<'tcx>(
|
|||
| ty::PredicateKind::TypeOutlives(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
|
||||
Some(OutlivesBound::RegionSubRegion(r_b, r_a))
|
||||
|
|
|
@ -153,6 +153,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
/// This function may have to perform normalizations, and hence it
|
||||
/// returns an `InferOk` with subobligations that must be
|
||||
/// processed.
|
||||
#[instrument(level = "debug", skip(self, region_bound_pairs_map))]
|
||||
pub fn process_registered_region_obligations(
|
||||
&self,
|
||||
region_bound_pairs_map: &FxHashMap<hir::HirId, RegionBoundPairs<'tcx>>,
|
||||
|
@ -164,8 +165,6 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
"cannot process registered region obligations in a snapshot"
|
||||
);
|
||||
|
||||
debug!(?param_env, "process_registered_region_obligations()");
|
||||
|
||||
let my_region_obligations = self.take_registered_region_obligations();
|
||||
|
||||
for (body_id, RegionObligation { sup_type, sub_region, origin }) in my_region_obligations {
|
||||
|
|
|
@ -2,6 +2,7 @@ use super::combine::{CombineFields, RelationDir};
|
|||
use super::SubregionOrigin;
|
||||
|
||||
use crate::infer::combine::ConstEquateRelation;
|
||||
use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::traits::Obligation;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
|
||||
|
@ -74,9 +75,8 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
debug!("{}.tys({:?}, {:?})", self.tag(), a, b);
|
||||
|
||||
if a == b {
|
||||
return Ok(a);
|
||||
}
|
||||
|
@ -84,6 +84,7 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
|
|||
let infcx = self.fields.infcx;
|
||||
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
|
||||
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
|
||||
|
||||
match (a.kind(), b.kind()) {
|
||||
(&ty::Infer(TyVar(_)), &ty::Infer(TyVar(_))) => {
|
||||
// Shouldn't have any LBR here, so we can safely put
|
||||
|
@ -121,6 +122,40 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
|
|||
Ok(self.tcx().ty_error())
|
||||
}
|
||||
|
||||
(&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
|
||||
self.fields.infcx.super_combine_tys(self, a, b)?;
|
||||
Ok(a)
|
||||
}
|
||||
(&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
|
||||
if self.fields.define_opaque_types && did.is_local() =>
|
||||
{
|
||||
let mut generalize = |ty, ty_is_expected| {
|
||||
let var = infcx.next_ty_var_id_in_universe(
|
||||
TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
span: self.fields.trace.cause.span,
|
||||
},
|
||||
ty::UniverseIndex::ROOT,
|
||||
);
|
||||
self.fields.instantiate(ty, RelationDir::SubtypeOf, var, ty_is_expected)?;
|
||||
Ok(infcx.tcx.mk_ty_var(var))
|
||||
};
|
||||
let (a, b) = if self.a_is_expected { (a, b) } else { (b, a) };
|
||||
let (a, b) = match (a.kind(), b.kind()) {
|
||||
(&ty::Opaque(..), _) => (a, generalize(b, true)?),
|
||||
(_, &ty::Opaque(..)) => (generalize(a, false)?, b),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.fields.obligations.push(infcx.opaque_ty_obligation(
|
||||
a,
|
||||
b,
|
||||
true,
|
||||
self.param_env(),
|
||||
self.fields.trace.cause.clone(),
|
||||
));
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
_ => {
|
||||
self.fields.infcx.super_combine_tys(self, a, b)?;
|
||||
Ok(a)
|
||||
|
|
|
@ -18,7 +18,7 @@ pub struct Snapshot<'tcx> {
|
|||
|
||||
/// Records the "undo" data for a single operation that affects some form of inference variable.
|
||||
pub(crate) enum UndoLog<'tcx> {
|
||||
OpaqueTypes(OpaqueTypeKey<'tcx>),
|
||||
OpaqueTypes(OpaqueTypeKey<'tcx>, usize),
|
||||
TypeVariables(type_variable::UndoLog<'tcx>),
|
||||
ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
|
||||
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
|
||||
|
@ -43,7 +43,6 @@ macro_rules! impl_from {
|
|||
|
||||
// Upcast from a single kind of "undoable action" to the general enum
|
||||
impl_from! {
|
||||
OpaqueTypes(OpaqueTypeKey<'tcx>),
|
||||
RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
|
||||
TypeVariables(type_variable::UndoLog<'tcx>),
|
||||
|
||||
|
@ -66,7 +65,7 @@ impl_from! {
|
|||
impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
|
||||
fn reverse(&mut self, undo: UndoLog<'tcx>) {
|
||||
match undo {
|
||||
UndoLog::OpaqueTypes(key) => self.opaque_type_storage.remove(key),
|
||||
UndoLog::OpaqueTypes(key, idx) => self.opaque_type_storage.remove(key, idx),
|
||||
UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo),
|
||||
UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo),
|
||||
UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo),
|
||||
|
|
|
@ -167,6 +167,9 @@ impl<'tcx> Elaborator<'tcx> {
|
|||
// Currently, we do not elaborate WF predicates,
|
||||
// although we easily could.
|
||||
}
|
||||
ty::PredicateKind::OpaqueType(..) => {
|
||||
todo!("{:#?}", obligation)
|
||||
}
|
||||
ty::PredicateKind::ObjectSafe(..) => {
|
||||
// Currently, we do not elaborate object-safe
|
||||
// predicates.
|
||||
|
|
|
@ -1654,6 +1654,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
|
|||
Coerce(..) |
|
||||
ConstEvaluatable(..) |
|
||||
ConstEquate(..) |
|
||||
OpaqueType(..) |
|
||||
TypeWellFormedFromEnv(..) => continue,
|
||||
};
|
||||
if predicate.is_global() {
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
use crate::infer::MemberConstraint;
|
||||
use crate::ty::subst::GenericArg;
|
||||
use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
|
||||
use crate::ty::{self, BoundVar, List, OpaqueTypeKey, Region, Ty, TyCtxt};
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_macros::HashStable;
|
||||
use smallvec::SmallVec;
|
||||
|
@ -178,6 +178,9 @@ pub struct QueryResponse<'tcx, R> {
|
|||
pub var_values: CanonicalVarValues<'tcx>,
|
||||
pub region_constraints: QueryRegionConstraints<'tcx>,
|
||||
pub certainty: Certainty,
|
||||
/// List of opaque types for which we figured out a hidden type
|
||||
/// during the evaluation of the query.
|
||||
pub opaque_types: Vec<(OpaqueTypeKey<'tcx>, Vec<Ty<'tcx>>)>,
|
||||
pub value: R,
|
||||
}
|
||||
|
||||
|
|
|
@ -53,17 +53,17 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
|
|||
self.relate(a, b)
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn regions(
|
||||
&mut self,
|
||||
a: ty::Region<'tcx>,
|
||||
b: ty::Region<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
||||
debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
debug!("{}.tys({:?}, {:?})", self.tag(), a, b);
|
||||
if a == b {
|
||||
return Ok(a);
|
||||
}
|
||||
|
|
|
@ -265,6 +265,10 @@ impl FlagComputation {
|
|||
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
|
||||
self.add_ty(ty);
|
||||
}
|
||||
ty::PredicateKind::OpaqueType(opaque, ty) => {
|
||||
self.add_ty(opaque);
|
||||
self.add_ty(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1207,15 +1207,11 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
|
|||
type BreakTy = FoundFlags;
|
||||
|
||||
#[inline]
|
||||
#[instrument(level = "trace")]
|
||||
fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<Self::BreakTy> {
|
||||
debug!(
|
||||
"HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}",
|
||||
t,
|
||||
t.flags(),
|
||||
self.flags
|
||||
);
|
||||
if t.flags().intersects(self.flags) {
|
||||
#[instrument(skip(self), level = "trace")]
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
let flags = t.flags();
|
||||
trace!(t.flags=?t.flags());
|
||||
if flags.intersects(self.flags) {
|
||||
ControlFlow::Break(FoundFlags)
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
|
@ -1235,7 +1231,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[instrument(level = "trace")]
|
||||
#[instrument(skip(self), level = "trace")]
|
||||
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
let flags = FlagComputation::for_const(c);
|
||||
trace!(r.flags=?flags);
|
||||
|
|
|
@ -628,6 +628,11 @@ pub enum PredicateKind<'tcx> {
|
|||
///
|
||||
/// Only used for Chalk.
|
||||
TypeWellFormedFromEnv(Ty<'tcx>),
|
||||
|
||||
/// Represents a hidden type assignment for an opaque type.
|
||||
/// Such obligations get processed by checking whether the item currently being
|
||||
/// type-checked may acually define it.
|
||||
OpaqueType(Ty<'tcx>, Ty<'tcx>),
|
||||
}
|
||||
|
||||
/// The crate outlives map is computed during typeck and contains the
|
||||
|
@ -987,6 +992,7 @@ impl<'tcx> Predicate<'tcx> {
|
|||
| PredicateKind::TypeOutlives(..)
|
||||
| PredicateKind::ConstEvaluatable(..)
|
||||
| PredicateKind::ConstEquate(..)
|
||||
| PredicateKind::OpaqueType(..)
|
||||
| PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
}
|
||||
}
|
||||
|
@ -1005,6 +1011,7 @@ impl<'tcx> Predicate<'tcx> {
|
|||
| PredicateKind::ClosureKind(..)
|
||||
| PredicateKind::ConstEvaluatable(..)
|
||||
| PredicateKind::ConstEquate(..)
|
||||
| PredicateKind::OpaqueType(..)
|
||||
| PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
}
|
||||
}
|
||||
|
@ -1045,7 +1052,18 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable, TypeFoldable)]
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
PartialEq,
|
||||
Eq,
|
||||
HashStable,
|
||||
TyEncodable,
|
||||
TyDecodable,
|
||||
TypeFoldable,
|
||||
Lift
|
||||
)]
|
||||
pub struct OpaqueTypeKey<'tcx> {
|
||||
pub def_id: DefId,
|
||||
pub substs: SubstsRef<'tcx>,
|
||||
|
|
|
@ -2607,6 +2607,9 @@ define_print_and_forward_display! {
|
|||
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
|
||||
p!("the type `", print(ty), "` is found in the environment")
|
||||
}
|
||||
ty::PredicateKind::OpaqueType(a, b) => {
|
||||
p!("opaque type assigment with `", print(a), "` == `", print(b) ,"`")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -191,6 +191,9 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
|
|||
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
|
||||
write!(f, "TypeWellFormedFromEnv({:?})", ty)
|
||||
}
|
||||
ty::PredicateKind::OpaqueType(a, b) => {
|
||||
write!(f, "OpaqueType({:?}, {:?})", a.kind(), b.kind())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -463,6 +466,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> {
|
|||
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
|
||||
tcx.lift(ty).map(ty::PredicateKind::TypeWellFormedFromEnv)
|
||||
}
|
||||
ty::PredicateKind::OpaqueType(opaque, ty) => {
|
||||
Some(ty::PredicateKind::OpaqueType(tcx.lift(opaque)?, tcx.lift(ty)?))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1816,6 +1816,13 @@ impl<'tcx> TyS<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn expect_opaque_type(&self) -> ty::OpaqueTypeKey<'tcx> {
|
||||
match *self.kind() {
|
||||
Opaque(def_id, substs) => ty::OpaqueTypeKey { def_id, substs },
|
||||
_ => bug!("`expect_opaque_type` called on non-opaque type: {}", self),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
|
||||
match self.kind() {
|
||||
Adt(def, substs) => {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use crate::build::matches::ArmHasGuard;
|
||||
use crate::build::ForGuard::OutsideGuard;
|
||||
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::thir::*;
|
||||
use rustc_middle::{mir::*, ty};
|
||||
use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN;
|
||||
use rustc_session::lint::Level;
|
||||
use rustc_span::Span;
|
||||
|
@ -192,7 +192,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
// This return type is usually `()`, unless the block is diverging, in which case the
|
||||
// return type is `!`. For the unit type, we need to actually return the unit, but in
|
||||
// the case of `!`, no return value is required, as the block will never return.
|
||||
if destination_ty.is_unit() {
|
||||
// Opaque types of empty bodies also need this unit assignment, in order to infer that their
|
||||
// type is actually unit. Otherwise there will be no defining use found in the MIR.
|
||||
if destination_ty.is_unit() || matches!(destination_ty.kind(), ty::Opaque(..)) {
|
||||
// We only want to assign an implicit `()` as the return value of the block if the
|
||||
// block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.)
|
||||
this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
|
||||
|
|
|
@ -186,7 +186,6 @@ impl<K: DepKind> EncoderState<K> {
|
|||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, record_graph))]
|
||||
fn encode_node(
|
||||
&mut self,
|
||||
node: &NodeInfo<K>,
|
||||
|
@ -213,7 +212,6 @@ impl<K: DepKind> EncoderState<K> {
|
|||
stat.edge_counter += edge_count as u64;
|
||||
}
|
||||
|
||||
debug!(?index, ?node);
|
||||
let encoder = &mut self.encoder;
|
||||
if self.result.is_ok() {
|
||||
self.result = node.encode(encoder);
|
||||
|
|
|
@ -359,6 +359,7 @@ crate fn required_region_bounds<'tcx>(
|
|||
| ty::PredicateKind::RegionOutlives(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
|
||||
// Search for a bound of the form `erased_self_ty
|
||||
|
|
|
@ -853,6 +853,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
|||
| ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -775,6 +775,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
|||
span,
|
||||
"TypeWellFormedFromEnv predicate should only exist in the environment"
|
||||
),
|
||||
|
||||
ty::PredicateKind::OpaqueType(..) => {
|
||||
todo!("{:#?}", obligation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -397,6 +397,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
|
|||
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
|
||||
bug!("TypeWellFormedFromEnv is only used for Chalk")
|
||||
}
|
||||
ty::PredicateKind::OpaqueType(..) => {
|
||||
todo!("{:#?}", obligation);
|
||||
}
|
||||
},
|
||||
Some(pred) => match pred {
|
||||
ty::PredicateKind::Trait(data) => {
|
||||
|
@ -642,6 +645,20 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
|
|||
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
|
||||
bug!("TypeWellFormedFromEnv is only used for Chalk")
|
||||
}
|
||||
ty::PredicateKind::OpaqueType(a, b) => {
|
||||
match self.selcx.infcx().handle_opaque_type(
|
||||
a,
|
||||
b,
|
||||
&obligation.cause,
|
||||
obligation.param_env,
|
||||
) {
|
||||
Ok(value) => ProcessResult::Changed(mk_pending(value)),
|
||||
Err(err) => ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError(
|
||||
ExpectedFound::new(true, a, b),
|
||||
err,
|
||||
)),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -313,6 +313,7 @@ fn predicate_references_self<'tcx>(
|
|||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
}
|
||||
}
|
||||
|
@ -347,6 +348,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
|||
| ty::PredicateKind::TypeOutlives(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
|
||||
}
|
||||
})
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::infer::{InferCtxt, InferOk};
|
|||
use crate::traits::engine::TraitEngineExt as _;
|
||||
use crate::traits::query::type_op::TypeOpOutput;
|
||||
use crate::traits::query::Fallible;
|
||||
use crate::traits::{ObligationCause, TraitEngine};
|
||||
use crate::traits::TraitEngine;
|
||||
use rustc_infer::traits::TraitEngineExt as _;
|
||||
use rustc_span::source_map::DUMMY_SP;
|
||||
|
||||
|
@ -60,7 +60,6 @@ fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
|
|||
op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
|
||||
) -> Fallible<TypeOpOutput<'tcx, Op>> {
|
||||
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
||||
let dummy_body_id = ObligationCause::dummy().body_id;
|
||||
|
||||
// During NLL, we expect that nobody will register region
|
||||
// obligations **except** as part of a custom type op (and, at the
|
||||
|
@ -75,7 +74,6 @@ fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
|
|||
);
|
||||
|
||||
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
|
||||
debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
|
||||
fulfill_cx.register_predicate_obligations(infcx, obligations);
|
||||
let errors = fulfill_cx.select_all_or_error(infcx);
|
||||
if !errors.is_empty() {
|
||||
|
|
|
@ -254,6 +254,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
};
|
||||
|
||||
if obligation.predicate.skip_binder().self_ty().is_ty_var() {
|
||||
debug!(ty = ?obligation.predicate.skip_binder().self_ty(), "ambiguous inference var or opaque type");
|
||||
// Self is a type variable (e.g., `_: AsRef<str>`).
|
||||
//
|
||||
// This is somewhat problematic, as the current scheme can't really
|
||||
|
|
|
@ -37,6 +37,7 @@ use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
|
|||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::thir::abstract_const::NotConstEvaluatable;
|
||||
use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
|
||||
use rustc_middle::ty::fold::BottomUpFolder;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
|
||||
|
@ -697,6 +698,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
|
||||
bug!("TypeWellFormedFromEnv is only used for chalk")
|
||||
}
|
||||
ty::PredicateKind::OpaqueType(a, b) => {
|
||||
match self.infcx().handle_opaque_type(
|
||||
a,
|
||||
b,
|
||||
&obligation.cause,
|
||||
obligation.param_env,
|
||||
) {
|
||||
Ok(obligations) => {
|
||||
self.evaluate_predicates_recursively(previous_stack, obligations)
|
||||
}
|
||||
Err(_) => Ok(EvaluatedToErr),
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1337,6 +1351,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(self, param_env, cache_fresh_trait_pred, dep_node), level = "debug")]
|
||||
fn insert_candidate_cache(
|
||||
&mut self,
|
||||
mut param_env: ty::ParamEnv<'tcx>,
|
||||
|
@ -1377,6 +1392,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
/// a projection, look at the bounds of `T::Bar`, see if we can find a
|
||||
/// `Baz` bound. We return indexes into the list returned by
|
||||
/// `tcx.item_bounds` for any applicable bounds.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn match_projection_obligation_against_definition_bounds(
|
||||
&mut self,
|
||||
obligation: &TraitObligation<'tcx>,
|
||||
|
@ -1384,10 +1400,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
let poly_trait_predicate = self.infcx().resolve_vars_if_possible(obligation.predicate);
|
||||
let placeholder_trait_predicate =
|
||||
self.infcx().replace_bound_vars_with_placeholders(poly_trait_predicate);
|
||||
debug!(
|
||||
?placeholder_trait_predicate,
|
||||
"match_projection_obligation_against_definition_bounds"
|
||||
);
|
||||
debug!(?placeholder_trait_predicate);
|
||||
|
||||
let tcx = self.infcx.tcx;
|
||||
let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() {
|
||||
|
@ -1438,7 +1451,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
})
|
||||
.collect();
|
||||
|
||||
debug!(?matching_bounds, "match_projection_obligation_against_definition_bounds");
|
||||
debug!(?matching_bounds);
|
||||
matching_bounds
|
||||
}
|
||||
|
||||
|
@ -1468,6 +1481,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
});
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.define_opaque_types(false)
|
||||
.sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
|
||||
.map(|InferOk { obligations: _, value: () }| {
|
||||
// This method is called within a probe, so we can't have
|
||||
|
@ -1523,6 +1537,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.define_opaque_types(false)
|
||||
.sup(obligation.predicate, infer_projection)
|
||||
.map_or(false, |InferOk { obligations, value: () }| {
|
||||
self.evaluate_predicates_recursively(
|
||||
|
@ -2081,11 +2096,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
match self.match_impl(impl_def_id, obligation) {
|
||||
Ok(substs) => substs,
|
||||
Err(()) => {
|
||||
bug!(
|
||||
"Impl {:?} was matchable against {:?} but now is not",
|
||||
impl_def_id,
|
||||
obligation
|
||||
self.infcx.tcx.sess.delay_span_bug(
|
||||
obligation.cause.span,
|
||||
&format!(
|
||||
"Impl {:?} was matchable against {:?} but now is not",
|
||||
impl_def_id, obligation
|
||||
),
|
||||
);
|
||||
let value = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id);
|
||||
let err = self.tcx().ty_error();
|
||||
let value = value.fold_with(&mut BottomUpFolder {
|
||||
tcx: self.tcx(),
|
||||
ty_op: |_| err,
|
||||
lt_op: |l| l,
|
||||
ct_op: |c| c,
|
||||
});
|
||||
Normalized { value, obligations: vec![] }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2222,6 +2248,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
|
||||
self.infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
// We don't want opaque types to just randomly match everything,
|
||||
// they should be opaque, even in their defining scope.
|
||||
.define_opaque_types(false)
|
||||
.sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
|
||||
.map(|InferOk { obligations, .. }| obligations)
|
||||
.map_err(|_| ())
|
||||
|
|
|
@ -146,6 +146,10 @@ pub fn predicate_obligations<'a, 'tcx>(
|
|||
wf.compute(c1.into());
|
||||
wf.compute(c2.into());
|
||||
}
|
||||
ty::PredicateKind::OpaqueType(opaque, ty) => {
|
||||
wf.compute(opaque.into());
|
||||
wf.compute(ty.into());
|
||||
}
|
||||
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
|
||||
bug!("TypeWellFormedFromEnv is only used for Chalk")
|
||||
}
|
||||
|
|
|
@ -110,6 +110,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
|
|||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", predicate),
|
||||
};
|
||||
|
@ -196,6 +197,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
|
|||
| ty::PredicateKind::Subtype(..)
|
||||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::ConstEquate(..) => {
|
||||
chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner))
|
||||
}
|
||||
|
@ -610,6 +612,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
|
|||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => {
|
||||
bug!("unexpected predicate {}", &self)
|
||||
}
|
||||
|
@ -739,6 +742,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru
|
|||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => {
|
||||
bug!("unexpected predicate {}", &self)
|
||||
}
|
||||
|
|
|
@ -142,6 +142,7 @@ crate fn evaluate_goal<'tcx>(
|
|||
var_values: CanonicalVarValues { var_values },
|
||||
region_constraints: QueryRegionConstraints::default(),
|
||||
certainty: Certainty::Proven,
|
||||
opaque_types: vec![],
|
||||
value: (),
|
||||
},
|
||||
};
|
||||
|
@ -170,6 +171,7 @@ crate fn evaluate_goal<'tcx>(
|
|||
.make_identity(tcx),
|
||||
region_constraints: QueryRegionConstraints::default(),
|
||||
certainty: Certainty::Ambiguous,
|
||||
opaque_types: vec![],
|
||||
value: (),
|
||||
},
|
||||
};
|
||||
|
|
|
@ -105,6 +105,7 @@ fn compute_implied_outlives_bounds<'tcx>(
|
|||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => vec![],
|
||||
ty::PredicateKind::WellFormed(arg) => {
|
||||
wf_args.push(arg);
|
||||
|
|
|
@ -69,6 +69,7 @@ fn not_outlives_predicate<'tcx>(p: &ty::Predicate<'tcx>) -> bool {
|
|||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => true,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,12 @@ bitflags! {
|
|||
| TypeFlags::HAS_CT_INFER.bits
|
||||
| TypeFlags::HAS_TY_PLACEHOLDER.bits
|
||||
| TypeFlags::HAS_CT_PLACEHOLDER.bits
|
||||
// Opaque types may get resolved in the current scope and must
|
||||
// thus not be transported to other queries if it can be avoided.
|
||||
// FIXME: differentiate between crate-local opaque types
|
||||
// and opaque types from other crates, as only opaque types
|
||||
// from the local crate can possibly be a local name
|
||||
| TypeFlags::HAS_TY_OPAQUE.bits
|
||||
// We consider 'freshened' types and constants
|
||||
// to depend on a particular fn.
|
||||
// The freshening process throws away information,
|
||||
|
|
|
@ -504,20 +504,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// provide a structured suggestion in that case.
|
||||
pub(crate) fn opt_suggest_box_span(
|
||||
&self,
|
||||
span: Span,
|
||||
_span: Span,
|
||||
outer_ty: &'tcx TyS<'tcx>,
|
||||
orig_expected: Expectation<'tcx>,
|
||||
) -> Option<Span> {
|
||||
match (orig_expected, self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty))) {
|
||||
(Expectation::ExpectHasType(expected), Some((_id, ty)))
|
||||
(Expectation::ExpectHasType(expected), Some((_id, _ty)))
|
||||
if self.in_tail_expr && self.can_coerce(outer_ty, expected) =>
|
||||
{
|
||||
let impl_trait_ret_ty =
|
||||
self.infcx.instantiate_opaque_types(self.body_id, self.param_env, ty, span);
|
||||
assert!(
|
||||
impl_trait_ret_ty.obligations.is_empty(),
|
||||
"we should never get new obligations here"
|
||||
);
|
||||
let obligations = self.fulfillment_cx.borrow().pending_obligations();
|
||||
let mut suggest_box = !obligations.is_empty();
|
||||
for o in obligations {
|
||||
|
|
|
@ -545,7 +545,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
expected: Expectation<'tcx>,
|
||||
fn_sig: ty::FnSig<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
// `fn_sig` is the *signature* of the cosure being called. We
|
||||
// `fn_sig` is the *signature* of the closure being called. We
|
||||
// don't know the full details yet (`Fn` vs `FnMut` etc), but we
|
||||
// do know the types expected for each argument and the return
|
||||
// type.
|
||||
|
|
|
@ -17,7 +17,7 @@ use rustc_middle::ty::fold::TypeFoldable;
|
|||
use rustc_middle::ty::layout::MAX_SIMD_LANES;
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::util::{Discr, IntTypeExt};
|
||||
use rustc_middle::ty::{self, OpaqueTypeKey, ParamEnv, RegionKind, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, ParamEnv, RegionKind, Ty, TyCtxt};
|
||||
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{self, MultiSpan, Span};
|
||||
|
@ -81,8 +81,6 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||
can_be_generator: Option<hir::Movability>,
|
||||
return_type_pre_known: bool,
|
||||
) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
|
||||
let mut fn_sig = fn_sig;
|
||||
|
||||
// Create the function context. This is either derived from scratch or,
|
||||
// in the case of closures, based on the outer context.
|
||||
let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
|
||||
|
@ -95,21 +93,13 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||
|
||||
let declared_ret_ty = fn_sig.output();
|
||||
|
||||
let revealed_ret_ty =
|
||||
fcx.instantiate_opaque_types_from_value(declared_ret_ty, decl.output.span());
|
||||
debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty);
|
||||
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty)));
|
||||
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(declared_ret_ty)));
|
||||
fcx.ret_type_span = Some(decl.output.span());
|
||||
if let ty::Opaque(..) = declared_ret_ty.kind() {
|
||||
// FIXME(oli-obk): remove this and have diagnostics check the signature's return type directly
|
||||
// as we don't reveal here anymore.
|
||||
fcx.ret_coercion_impl_trait = Some(declared_ret_ty);
|
||||
}
|
||||
fn_sig = tcx.mk_fn_sig(
|
||||
fn_sig.inputs().iter().cloned(),
|
||||
revealed_ret_ty,
|
||||
fn_sig.c_variadic,
|
||||
fn_sig.unsafety,
|
||||
fn_sig.abi,
|
||||
);
|
||||
|
||||
let span = body.value.span;
|
||||
|
||||
|
@ -251,7 +241,7 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||
fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span });
|
||||
debug!("actual_return_ty replaced with {:?}", actual_return_ty);
|
||||
}
|
||||
fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty);
|
||||
fcx.demand_suptype(span, declared_ret_ty, actual_return_ty);
|
||||
|
||||
// Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
|
||||
if let Some(panic_impl_did) = tcx.lang_items().panic_impl() {
|
||||
|
@ -629,6 +619,8 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||
span: Span,
|
||||
origin: &hir::OpaqueTyOrigin,
|
||||
) {
|
||||
let hidden_type = tcx.type_of(def_id).subst(tcx, substs);
|
||||
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let defining_use_anchor = match *origin {
|
||||
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
|
||||
|
@ -643,23 +635,12 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||
|
||||
let misc_cause = traits::ObligationCause::misc(span, hir_id);
|
||||
|
||||
let _ = inh.register_infer_ok_obligations(
|
||||
infcx.instantiate_opaque_types(hir_id, param_env, opaque_ty, span),
|
||||
);
|
||||
|
||||
for (OpaqueTypeKey { def_id, substs }, opaque_defn) in infcx.opaque_types() {
|
||||
let hidden_type = tcx.type_of(def_id).subst(tcx, substs);
|
||||
trace!(?hidden_type);
|
||||
match infcx.at(&misc_cause, param_env).eq(opaque_defn.concrete_ty, hidden_type) {
|
||||
Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
|
||||
Err(ty_err) => tcx.sess.delay_span_bug(
|
||||
span,
|
||||
&format!(
|
||||
"could not check bounds on revealed type `{}`:\n{}",
|
||||
hidden_type, ty_err,
|
||||
),
|
||||
),
|
||||
}
|
||||
match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_type) {
|
||||
Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
|
||||
Err(ty_err) => tcx.sess.delay_span_bug(
|
||||
span,
|
||||
&format!("could not unify `{}` with revealed type:\n{}", hidden_type, ty_err,),
|
||||
),
|
||||
}
|
||||
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
|
@ -671,7 +652,7 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||
|
||||
match origin {
|
||||
// Checked when type checking the function containing them.
|
||||
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => return,
|
||||
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
|
||||
// Can have different predicates to their defining use
|
||||
hir::OpaqueTyOrigin::TyAlias => {
|
||||
// Finally, resolve all regions. This catches wily misuses of
|
||||
|
@ -680,6 +661,9 @@ fn check_opaque_meets_bounds<'tcx>(
|
|||
fcx.regionck_item(hir_id, span, FxHashSet::default());
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up after ourselves
|
||||
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -3,16 +3,20 @@
|
|||
use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
|
||||
|
||||
use crate::astconv::AstConv;
|
||||
use crate::rustc_middle::ty::subst::Subst;
|
||||
use hir::OpaqueTyOrigin;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||
use rustc_infer::infer::{InferOk, InferResult};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::subst::InternalSubsts;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::traits::error_reporting::ArgKind;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
|
@ -172,6 +176,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
expected_ty: Ty<'tcx>,
|
||||
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
||||
match *expected_ty.kind() {
|
||||
ty::Opaque(def_id, substs) => {
|
||||
let bounds = self.tcx.explicit_item_bounds(def_id);
|
||||
let sig = bounds.iter().find_map(|(pred, span)| match pred.kind().skip_binder() {
|
||||
ty::PredicateKind::Projection(proj_predicate) => self
|
||||
.deduce_sig_from_projection(
|
||||
Some(*span),
|
||||
pred.kind().rebind(proj_predicate.subst(self.tcx, substs)),
|
||||
),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
let kind = bounds
|
||||
.iter()
|
||||
.filter_map(|(pred, _)| match pred.kind().skip_binder() {
|
||||
ty::PredicateKind::Trait(tp) => {
|
||||
self.tcx.fn_trait_kind_from_lang_item(tp.def_id())
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
|
||||
trace!(?sig, ?kind);
|
||||
(sig, kind)
|
||||
}
|
||||
ty::Dynamic(ref object_type, ..) => {
|
||||
let sig = object_type.projection_bounds().find_map(|pb| {
|
||||
let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self);
|
||||
|
@ -197,10 +224,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
||||
let expected_sig =
|
||||
self.obligations_for_self_ty(expected_vid).find_map(|(_, obligation)| {
|
||||
debug!(
|
||||
"deduce_expectations_from_obligations: obligation.predicate={:?}",
|
||||
obligation.predicate
|
||||
);
|
||||
debug!(?obligation.predicate);
|
||||
|
||||
let bound_predicate = obligation.predicate.kind();
|
||||
if let ty::PredicateKind::Projection(proj_predicate) =
|
||||
|
@ -401,9 +425,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// in this binder we are creating.
|
||||
assert!(!expected_sig.sig.skip_binder().has_vars_bound_above(ty::INNERMOST));
|
||||
let bound_sig = expected_sig.sig.map_bound(|sig| {
|
||||
let output = self.hide_parent_opaque_types(
|
||||
sig.output(),
|
||||
expected_sig.cause_span.unwrap_or(DUMMY_SP),
|
||||
body.id().hir_id,
|
||||
);
|
||||
self.tcx.mk_fn_sig(
|
||||
sig.inputs().iter().cloned(),
|
||||
sig.output(),
|
||||
output,
|
||||
sig.c_variadic,
|
||||
hir::Unsafety::Normal,
|
||||
Abi::RustCall,
|
||||
|
@ -590,6 +619,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
_ => astconv.ty_infer(None, decl.output.span()),
|
||||
},
|
||||
};
|
||||
let supplied_return =
|
||||
self.hide_parent_opaque_types(supplied_return, decl.output.span(), body.id().hir_id);
|
||||
|
||||
let result = ty::Binder::bind_with_vars(
|
||||
self.tcx.mk_fn_sig(
|
||||
|
@ -610,27 +641,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
result
|
||||
}
|
||||
|
||||
fn hide_parent_opaque_types(&self, ty: Ty<'tcx>, span: Span, body_id: hir::HirId) -> Ty<'tcx> {
|
||||
ty.fold_with(&mut ty::fold::BottomUpFolder {
|
||||
tcx: self.infcx.tcx,
|
||||
lt_op: |lt| lt,
|
||||
ct_op: |ct| ct,
|
||||
ty_op: |ty| match *ty.kind() {
|
||||
// Closures can't create hidden types for opaque types of their parent, as they
|
||||
// do not have all the outlives information available. Also `type_of` looks for
|
||||
// hidden types in the owner (so the closure's parent), so it would not find these
|
||||
// definitions.
|
||||
ty::Opaque(def_id, _substs)
|
||||
if matches!(
|
||||
self.infcx.opaque_type_origin(def_id, DUMMY_SP),
|
||||
Some(OpaqueTyOrigin::FnReturn(..))
|
||||
) =>
|
||||
{
|
||||
let ty_var = self.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::TypeInference,
|
||||
span,
|
||||
});
|
||||
let cause = ObligationCause::misc(span, body_id);
|
||||
self.register_predicates(vec![self.infcx.opaque_ty_obligation(
|
||||
ty,
|
||||
ty_var,
|
||||
true,
|
||||
self.param_env,
|
||||
cause,
|
||||
)]);
|
||||
ty_var
|
||||
}
|
||||
_ => ty,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/// Invoked when we are translating the generator that results
|
||||
/// from desugaring an `async fn`. Returns the "sugared" return
|
||||
/// type of the `async fn` -- that is, the return type that the
|
||||
/// user specified. The "desugared" return type is an `impl
|
||||
/// Future<Output = T>`, so we do this by searching through the
|
||||
/// obligations to extract the `T`.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn deduce_future_output_from_obligations(&self, expr_def_id: DefId) -> Option<Ty<'tcx>> {
|
||||
debug!("deduce_future_output_from_obligations(expr_def_id={:?})", expr_def_id);
|
||||
|
||||
let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| {
|
||||
span_bug!(self.tcx.def_span(expr_def_id), "async fn generator outside of a fn")
|
||||
});
|
||||
|
||||
// In practice, the return type of the surrounding function is
|
||||
// always a (not yet resolved) inference variable, because it
|
||||
// is the hidden type for an `impl Trait` that we are going to
|
||||
// be inferring.
|
||||
let ret_ty = ret_coercion.borrow().expected_ty();
|
||||
let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
|
||||
let ret_vid = match *ret_ty.kind() {
|
||||
ty::Infer(ty::TyVar(ret_vid)) => ret_vid,
|
||||
let (def_id, substs) = match *ret_ty.kind() {
|
||||
ty::Opaque(def_id, substs) => (def_id, substs),
|
||||
ty::Error(_) => return None,
|
||||
_ => span_bug!(
|
||||
self.tcx.def_span(expr_def_id),
|
||||
|
@ -638,17 +699,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
),
|
||||
};
|
||||
|
||||
let item_bounds = self.tcx.explicit_item_bounds(def_id);
|
||||
|
||||
// Search for a pending obligation like
|
||||
//
|
||||
// `<R as Future>::Output = T`
|
||||
//
|
||||
// where R is the return type we are expecting. This type `T`
|
||||
// will be our output.
|
||||
let output_ty = self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| {
|
||||
let bound_predicate = obligation.predicate.kind();
|
||||
let output_ty = item_bounds.iter().find_map(|&(predicate, span)| {
|
||||
let bound_predicate = predicate.subst(self.tcx, substs).kind();
|
||||
if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() {
|
||||
self.deduce_future_output_from_projection(
|
||||
obligation.cause.span,
|
||||
span,
|
||||
bound_predicate.rebind(proj_predicate),
|
||||
)
|
||||
} else {
|
||||
|
|
|
@ -1275,7 +1275,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
|
||||
/// Returns the current "merged type", representing our best-guess
|
||||
/// at the LUB of the expressions we've seen so far (if any). This
|
||||
/// isn't *final* until you call `self.final()`, which will return
|
||||
/// isn't *final* until you call `self.complete()`, which will return
|
||||
/// the merged type.
|
||||
pub fn merged_ty(&self) -> Ty<'tcx> {
|
||||
self.final_ty.unwrap_or(self.expected_ty)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_span::{self, Span};
|
||||
|
||||
use super::Expectation::*;
|
||||
|
@ -43,7 +44,7 @@ impl<'a, 'tcx> Expectation<'tcx> {
|
|||
// when checking the 'then' block which are incompatible with the
|
||||
// 'else' branch.
|
||||
pub(super) fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
|
||||
match *self {
|
||||
match self.strip_opaque(fcx) {
|
||||
ExpectHasType(ety) => {
|
||||
let ety = fcx.shallow_resolve(ety);
|
||||
if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation }
|
||||
|
@ -104,14 +105,35 @@ impl<'a, 'tcx> Expectation<'tcx> {
|
|||
/// for the program to type-check). `only_has_type` will return
|
||||
/// such a constraint, if it exists.
|
||||
pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
|
||||
match self {
|
||||
ExpectHasType(ty) => Some(fcx.resolve_vars_if_possible(ty)),
|
||||
match self.strip_opaque(fcx) {
|
||||
ExpectHasType(ty) => Some(ty),
|
||||
NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) | IsLast(_) => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// We must not treat opaque types as expected types in their defining scope, as that
|
||||
/// will break `fn foo() -> impl Trait { if cond { a } else { b } }` if `a` and `b` are
|
||||
/// only "equal" if they coerce to a common target, like two different function items
|
||||
/// coercing to a function pointer if they have the same signature.
|
||||
fn strip_opaque(self, fcx: &FnCtxt<'a, 'tcx>) -> Self {
|
||||
match self {
|
||||
ExpectHasType(ty) => {
|
||||
let ty = fcx.resolve_vars_if_possible(ty);
|
||||
match *ty.kind() {
|
||||
ty::Opaque(def_id, _)
|
||||
if fcx.infcx.opaque_type_origin(def_id, DUMMY_SP).is_some() =>
|
||||
{
|
||||
NoExpectation
|
||||
}
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
|
||||
/// Like `only_has_type`, but instead of returning `None` if no
|
||||
/// hard constraint exists, creates a fresh type variable.
|
||||
pub(super) fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> {
|
||||
|
|
|
@ -24,7 +24,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
self.fulfillment_cx.borrow_mut().pending_obligations()
|
||||
);
|
||||
|
||||
// Check if we have any unsolved varibales. If not, no need for fallback.
|
||||
// Check if we have any unsolved variables. If not, no need for fallback.
|
||||
let unsolved_variables = self.unsolved_variables();
|
||||
if unsolved_variables.is_empty() {
|
||||
return false;
|
||||
|
@ -66,16 +66,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
// refer to opaque types.
|
||||
self.select_obligations_where_possible(fallback_has_occurred, |_| {});
|
||||
|
||||
// We now run fallback again, but this time we allow it to replace
|
||||
// unconstrained opaque type variables, in addition to performing
|
||||
// other kinds of fallback.
|
||||
for ty in &self.unsolved_variables() {
|
||||
fallback_has_occurred |= self.fallback_opaque_type_vars(ty);
|
||||
}
|
||||
|
||||
// See if we can make any more progress.
|
||||
self.select_obligations_where_possible(fallback_has_occurred, |_| {});
|
||||
|
||||
fallback_has_occurred
|
||||
}
|
||||
|
||||
|
@ -136,59 +126,6 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
true
|
||||
}
|
||||
|
||||
/// Second round of fallback: Unconstrained type variables created
|
||||
/// from the instantiation of an opaque type fall back to the
|
||||
/// opaque type itself. This is a somewhat incomplete attempt to
|
||||
/// manage "identity passthrough" for `impl Trait` types.
|
||||
///
|
||||
/// For example, in this code:
|
||||
///
|
||||
///```
|
||||
/// type MyType = impl Copy;
|
||||
/// fn defining_use() -> MyType { true }
|
||||
/// fn other_use() -> MyType { defining_use() }
|
||||
/// ```
|
||||
///
|
||||
/// `defining_use` will constrain the instantiated inference
|
||||
/// variable to `bool`, while `other_use` will constrain
|
||||
/// the instantiated inference variable to `MyType`.
|
||||
///
|
||||
/// When we process opaque types during writeback, we
|
||||
/// will handle cases like `other_use`, and not count
|
||||
/// them as defining usages
|
||||
///
|
||||
/// However, we also need to handle cases like this:
|
||||
///
|
||||
/// ```rust
|
||||
/// pub type Foo = impl Copy;
|
||||
/// fn produce() -> Option<Foo> {
|
||||
/// None
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// In the above snippet, the inference variable created by
|
||||
/// instantiating `Option<Foo>` will be completely unconstrained.
|
||||
/// We treat this as a non-defining use by making the inference
|
||||
/// variable fall back to the opaque type itself.
|
||||
fn fallback_opaque_type_vars(&self, ty: Ty<'tcx>) -> bool {
|
||||
let span = self
|
||||
.infcx
|
||||
.type_var_origin(ty)
|
||||
.map(|origin| origin.span)
|
||||
.unwrap_or(rustc_span::DUMMY_SP);
|
||||
let oty = self.inner.borrow().opaque_type_storage.get_opaque_type_for_infer_var(ty);
|
||||
if let Some(opaque_ty) = oty {
|
||||
debug!(
|
||||
"fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}",
|
||||
ty, opaque_ty
|
||||
);
|
||||
self.demand_eqtype(span, ty, opaque_ty);
|
||||
true
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// The "diverging fallback" system is rather complicated. This is
|
||||
/// a result of our need to balance 'do the right thing' with
|
||||
/// backwards compatibility.
|
||||
|
@ -281,7 +218,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
.diverging_type_vars
|
||||
.borrow()
|
||||
.iter()
|
||||
.map(|&ty| self.infcx.shallow_resolve(ty))
|
||||
.map(|(&ty, _)| self.infcx.shallow_resolve(ty))
|
||||
.filter_map(|ty| ty.ty_vid())
|
||||
.map(|vid| self.infcx.root_var(vid))
|
||||
.collect();
|
||||
|
|
|
@ -274,7 +274,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
for a in &adj {
|
||||
if let Adjust::NeverToAny = a.kind {
|
||||
if a.target.is_ty_var() {
|
||||
self.diverging_type_vars.borrow_mut().insert(a.target);
|
||||
self.diverging_type_vars.borrow_mut().insert(a.target, expr.span);
|
||||
debug!("apply_adjustments: adding `{:?}` as diverging type var", a.target);
|
||||
}
|
||||
}
|
||||
|
@ -367,23 +367,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
(result, spans)
|
||||
}
|
||||
|
||||
/// Replaces the opaque types from the given value with type variables,
|
||||
/// and records the `OpaqueTypeMap` for later use during writeback. See
|
||||
/// `InferCtxt::instantiate_opaque_types` for more details.
|
||||
#[instrument(skip(self, value_span), level = "debug")]
|
||||
pub(in super::super) fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>(
|
||||
&self,
|
||||
value: T,
|
||||
value_span: Span,
|
||||
) -> T {
|
||||
self.register_infer_ok_obligations(self.instantiate_opaque_types(
|
||||
self.body_id,
|
||||
self.param_env,
|
||||
value,
|
||||
value_span,
|
||||
))
|
||||
}
|
||||
|
||||
/// Convenience method which tracks extra diagnostic information for normalization
|
||||
/// that occurs as a result of WF checking. The `hir_id` is the `HirId` of the hir item
|
||||
/// whose type is being wf-checked - this is used to construct a more precise span if
|
||||
|
@ -720,6 +703,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// inference variable.
|
||||
ty::PredicateKind::ClosureKind(..) => None,
|
||||
ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
ty::PredicateKind::OpaqueType(..) => None,
|
||||
}
|
||||
})
|
||||
.filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::callee::DeferredCallResolution;
|
||||
use super::MaybeInProgressTables;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefIdMap, LocalDefId};
|
||||
use rustc_hir::HirIdMap;
|
||||
|
@ -58,7 +58,7 @@ pub struct Inherited<'a, 'tcx> {
|
|||
/// Whenever we introduce an adjustment from `!` into a type variable,
|
||||
/// we record that type variable here. This is later used to inform
|
||||
/// fallback. See the `fallback` module for details.
|
||||
pub(super) diverging_type_vars: RefCell<FxHashSet<Ty<'tcx>>>,
|
||||
pub(super) diverging_type_vars: RefCell<FxHashMap<Ty<'tcx>, Span>>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> {
|
||||
|
@ -95,6 +95,13 @@ impl<'tcx> InheritedBuilder<'tcx> {
|
|||
let def_id = self.def_id;
|
||||
self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id)))
|
||||
}
|
||||
|
||||
/// WF-checking doesn't need to recompute opaque types and can instead use
|
||||
/// the type_of query to get them from typeck.
|
||||
pub fn reveal_defining_opaque_types(mut self) -> Self {
|
||||
self.infcx = self.infcx.reveal_defining_opaque_types();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Inherited<'a, 'tcx> {
|
||||
|
@ -119,8 +126,8 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(super) fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) {
|
||||
debug!("register_predicate({:?})", obligation);
|
||||
if obligation.has_escaping_bound_vars() {
|
||||
span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation);
|
||||
}
|
||||
|
|
|
@ -858,6 +858,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
| ty::PredicateKind::TypeOutlives(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
}
|
||||
});
|
||||
|
@ -1477,6 +1478,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
TraitCandidate(trait_ref) => self.probe(|_| {
|
||||
let _ = self
|
||||
.at(&ObligationCause::dummy(), self.param_env)
|
||||
.define_opaque_types(false)
|
||||
.sup(candidate.xform_self_ty, self_ty);
|
||||
match self.select_trait_candidate(trait_ref) {
|
||||
Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => {
|
||||
|
@ -1506,6 +1508,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
// First check that the self type can be related.
|
||||
let sub_obligations = match self
|
||||
.at(&ObligationCause::dummy(), self.param_env)
|
||||
.define_opaque_types(false)
|
||||
.sup(probe.xform_self_ty, self_ty)
|
||||
{
|
||||
Ok(InferOk { obligations, value: () }) => obligations,
|
||||
|
@ -1653,6 +1656,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
);
|
||||
if self
|
||||
.at(&ObligationCause::dummy(), self.param_env)
|
||||
.define_opaque_types(false)
|
||||
.sup(return_ty, xform_ret_ty)
|
||||
.is_err()
|
||||
{
|
||||
|
|
|
@ -99,6 +99,8 @@ pub use diverges::Diverges;
|
|||
pub use expectation::Expectation;
|
||||
pub use fn_ctxt::*;
|
||||
pub use inherited::{Inherited, InheritedBuilder};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use traits::ObligationCauseCode::MiscObligation;
|
||||
|
||||
use crate::astconv::AstConv;
|
||||
use crate::check::gather_locals::GatherLocalsVisitor;
|
||||
|
@ -341,6 +343,7 @@ fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::T
|
|||
typeck_with_fallback(tcx, def_id, fallback)
|
||||
}
|
||||
|
||||
#[instrument(skip(tcx, fallback))]
|
||||
fn typeck_with_fallback<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
|
@ -471,6 +474,19 @@ fn typeck_with_fallback<'tcx>(
|
|||
fcx.require_type_is_sized(ty, span, code);
|
||||
}
|
||||
|
||||
let opaque_types = fcx.infcx.inner.borrow_mut().opaque_type_storage.opaque_types();
|
||||
for (_, decl) in opaque_types {
|
||||
let cause = ObligationCause::new(body.value.span, id, MiscObligation);
|
||||
if let Err((err, expected, actual)) =
|
||||
decl.hidden_type(&fcx.infcx, &cause, fcx.param_env)
|
||||
{
|
||||
let cause = ObligationCause::new(actual.span, id, MiscObligation);
|
||||
fcx.report_mismatched_types(&cause, expected.ty, actual.ty, err)
|
||||
.span_label(expected.span, "type expected due to this")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
fcx.select_all_obligations_or_error();
|
||||
|
||||
if fn_sig.is_some() {
|
||||
|
|
|
@ -895,7 +895,7 @@ fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>) -> CheckWfFcxBuilder<
|
|||
|
||||
fn for_id(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> CheckWfFcxBuilder<'_> {
|
||||
CheckWfFcxBuilder {
|
||||
inherited: Inherited::build(tcx, def_id),
|
||||
inherited: Inherited::build(tcx, def_id).reveal_defining_opaque_types(),
|
||||
id: hir::HirId::make_owner(def_id),
|
||||
span,
|
||||
param_env: tcx.param_env(def_id),
|
||||
|
|
|
@ -18,7 +18,6 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
|||
use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::opaque_types::InferCtxtExt;
|
||||
|
||||
use std::mem;
|
||||
|
||||
|
@ -65,7 +64,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
wbcx.visit_closures();
|
||||
wbcx.visit_liberated_fn_sigs();
|
||||
wbcx.visit_fru_field_types();
|
||||
wbcx.visit_opaque_types(body.value.span);
|
||||
wbcx.visit_opaque_types();
|
||||
wbcx.visit_coercion_casts();
|
||||
wbcx.visit_user_provided_tys();
|
||||
wbcx.visit_user_provided_sigs();
|
||||
|
@ -496,65 +495,12 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
fcx_typeck_results.generator_interior_types.clone();
|
||||
}
|
||||
|
||||
#[instrument(skip(self, span), level = "debug")]
|
||||
fn visit_opaque_types(&mut self, span: Span) {
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn visit_opaque_types(&mut self) {
|
||||
let opaque_types =
|
||||
self.fcx.infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
|
||||
for (opaque_type_key, opaque_defn) in opaque_types {
|
||||
let hir_id =
|
||||
self.tcx().hir().local_def_id_to_hir_id(opaque_type_key.def_id.expect_local());
|
||||
let instantiated_ty = self.resolve(opaque_defn.concrete_ty, &hir_id);
|
||||
|
||||
debug_assert!(!instantiated_ty.has_escaping_bound_vars());
|
||||
|
||||
let opaque_type_key = self.fcx.fully_resolve(opaque_type_key).unwrap();
|
||||
|
||||
// Prevent:
|
||||
// * `fn foo<T>() -> Foo<T>`
|
||||
// * `fn foo<T: Bound + Other>() -> Foo<T>`
|
||||
// from being defining.
|
||||
|
||||
// Also replace all generic params with the ones from the opaque type
|
||||
// definition so that
|
||||
// ```rust
|
||||
// type Foo<T> = impl Baz + 'static;
|
||||
// fn foo<U>() -> Foo<U> { .. }
|
||||
// ```
|
||||
// figures out the concrete type with `U`, but the stored type is with `T`.
|
||||
|
||||
// FIXME: why are we calling this here? This seems too early, and duplicated.
|
||||
let definition_ty = self.fcx.infer_opaque_definition_from_instantiation(
|
||||
opaque_type_key,
|
||||
instantiated_ty,
|
||||
span,
|
||||
);
|
||||
|
||||
let mut skip_add = false;
|
||||
|
||||
if let ty::Opaque(definition_ty_def_id, _substs) = *definition_ty.kind() {
|
||||
if opaque_defn.origin == hir::OpaqueTyOrigin::TyAlias {
|
||||
if opaque_type_key.def_id == definition_ty_def_id {
|
||||
debug!(
|
||||
"skipping adding concrete definition for opaque type {:?} {:?}",
|
||||
opaque_defn, opaque_type_key.def_id
|
||||
);
|
||||
skip_add = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if opaque_type_key.substs.needs_infer() {
|
||||
span_bug!(span, "{:#?} has inference variables", opaque_type_key.substs)
|
||||
}
|
||||
|
||||
// We only want to add an entry into `concrete_opaque_types`
|
||||
// if we actually found a defining usage of this opaque type.
|
||||
// Otherwise, we do nothing - we'll either find a defining usage
|
||||
// in some other location, or we'll end up emitting an error due
|
||||
// to the lack of defining usage
|
||||
if !skip_add {
|
||||
self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id);
|
||||
}
|
||||
for (opaque_type_key, _) in opaque_types {
|
||||
self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -389,13 +389,6 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
|||
.get_value_matching(|(key, _)| key.def_id == def_id.to_def_id())
|
||||
.copied()
|
||||
.unwrap_or_else(|| {
|
||||
tcx.sess.delay_span_bug(
|
||||
DUMMY_SP,
|
||||
&format!(
|
||||
"owner {:?} has no opaque type for {:?} in its typeck results",
|
||||
owner, def_id,
|
||||
),
|
||||
);
|
||||
if let Some(ErrorReported) =
|
||||
tcx.typeck(owner).tainted_by_errors
|
||||
{
|
||||
|
@ -405,12 +398,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
|
|||
tcx.ty_error()
|
||||
} else {
|
||||
// We failed to resolve the opaque type or it
|
||||
// resolves to itself. Return the non-revealed
|
||||
// type, which should result in E0720.
|
||||
tcx.mk_opaque(
|
||||
def_id.to_def_id(),
|
||||
InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
|
||||
)
|
||||
// resolves to itself. We interpret this as the
|
||||
// no values of the hidden type ever being constructed,
|
||||
// so we can just make the hidden type be `!`.
|
||||
// For backwards compatibility reasons, we fall back to
|
||||
// `()` until we the diverging default is changed.
|
||||
tcx.mk_diverging_default()
|
||||
}
|
||||
});
|
||||
debug!("concrete_ty = {:?}", concrete_ty);
|
||||
|
@ -658,7 +651,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
|
|||
intravisit::walk_expr(self, ex);
|
||||
}
|
||||
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
|
||||
debug!("find_existential_constraints: visiting {:?}", it);
|
||||
trace!(?it.def_id);
|
||||
// The opaque type itself or its children are not within its reveal scope.
|
||||
if it.def_id.to_def_id() != self.def_id {
|
||||
self.check(it.def_id);
|
||||
|
@ -666,7 +659,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
|
|||
}
|
||||
}
|
||||
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
|
||||
debug!("find_existential_constraints: visiting {:?}", it);
|
||||
trace!(?it.def_id);
|
||||
// The opaque type itself or its children are not within its reveal scope.
|
||||
if it.def_id.to_def_id() != self.def_id {
|
||||
self.check(it.def_id);
|
||||
|
@ -674,7 +667,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
|
|||
}
|
||||
}
|
||||
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
|
||||
debug!("find_existential_constraints: visiting {:?}", it);
|
||||
trace!(?it.def_id);
|
||||
self.check(it.def_id);
|
||||
intravisit::walk_trait_item(self, it);
|
||||
}
|
||||
|
@ -684,12 +677,12 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
|
|||
let scope = tcx.hir().get_defining_scope(hir_id);
|
||||
let mut locator = ConstraintLocator { def_id: def_id.to_def_id(), tcx, found: None };
|
||||
|
||||
debug!("find_opaque_ty_constraints: scope={:?}", scope);
|
||||
debug!(?scope);
|
||||
|
||||
if scope == hir::CRATE_HIR_ID {
|
||||
tcx.hir().walk_toplevel_module(&mut locator);
|
||||
} else {
|
||||
debug!("find_opaque_ty_constraints: scope={:?}", tcx.hir().get(scope));
|
||||
trace!("scope={:#?}", tcx.hir().get(scope));
|
||||
match tcx.hir().get(scope) {
|
||||
// We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods
|
||||
// This allows our visitor to process the defining item itself, causing
|
||||
|
|
|
@ -427,6 +427,7 @@ fn trait_predicate_kind<'tcx>(
|
|||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
|
|||
| ty::PredicateKind::Coerce(..)
|
||||
| ty::PredicateKind::ConstEvaluatable(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => (),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -297,6 +297,7 @@ impl<'a> Clean<Option<WherePredicate>> for ty::Predicate<'a> {
|
|||
| ty::PredicateKind::ObjectSafe(..)
|
||||
| ty::PredicateKind::ClosureKind(..)
|
||||
| ty::PredicateKind::ConstEquate(..)
|
||||
| ty::PredicateKind::OpaqueType(..)
|
||||
| ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -305,7 +305,7 @@ pub fn return_impl_trait() -> i32 {
|
|||
}
|
||||
|
||||
#[cfg(not(any(cfail1,cfail4)))]
|
||||
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, typeck, fn_sig")]
|
||||
#[rustc_clean(cfg = "cfail2", except = "hir_owner, hir_owner_nodes, typeck, fn_sig, optimized_mir")]
|
||||
#[rustc_clean(cfg = "cfail3")]
|
||||
#[rustc_clean(cfg = "cfail5", except = "hir_owner, hir_owner_nodes, typeck, fn_sig, optimized_mir")]
|
||||
#[rustc_clean(cfg = "cfail6")]
|
||||
|
|
|
@ -28,9 +28,10 @@ impl Bar for AssocNoCopy {
|
|||
|
||||
impl Thing for AssocNoCopy {
|
||||
type Out = Box<dyn Bar<Assoc: Copy>>;
|
||||
//~^ ERROR could not find defining uses
|
||||
|
||||
fn func() -> Self::Out {
|
||||
//~^ ERROR the trait bound `String: Copy` is not satisfied
|
||||
Box::new(AssocNoCopy)
|
||||
//~^ ERROR the trait bound `String: Copy` is not satisfied
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
error[E0277]: the trait bound `String: Copy` is not satisfied
|
||||
--> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:32:18
|
||||
--> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:34:9
|
||||
|
|
||||
LL | fn func() -> Self::Out {
|
||||
| ^^^^^^^^^ the trait `Copy` is not implemented for `String`
|
||||
LL | Box::new(AssocNoCopy)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
|
||||
|
|
||||
= note: required for the cast to the object type `dyn Bar<Assoc = impl Copy>`
|
||||
|
||||
error: aborting due to previous error
|
||||
error: could not find defining uses
|
||||
--> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:30:28
|
||||
|
|
||||
LL | type Out = Box<dyn Bar<Assoc: Copy>>;
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
|
|
@ -23,8 +23,8 @@ fn bar() -> impl Bar {
|
|||
}
|
||||
|
||||
fn baz() -> impl Bar<Item = i32> {
|
||||
//~^ ERROR type mismatch resolving `<impl Bar as Foo>::Item == i32`
|
||||
bar()
|
||||
//~^ ERROR type mismatch resolving `<impl Bar as Foo>::Item == i32`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
error[E0271]: type mismatch resolving `<impl Bar as Foo>::Item == i32`
|
||||
--> $DIR/impl-trait-return-missing-constraint.rs:25:13
|
||||
--> $DIR/impl-trait-return-missing-constraint.rs:26:5
|
||||
|
|
||||
LL | fn bar() -> impl Bar {
|
||||
| -------- the found opaque type
|
||||
| -------- the expected opaque type
|
||||
...
|
||||
LL | fn baz() -> impl Bar<Item = i32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found associated type
|
||||
LL | bar()
|
||||
| ^^^^^ expected associated type, found `i32`
|
||||
|
|
||||
= note: expected type `i32`
|
||||
found associated type `<impl Bar as Foo>::Item`
|
||||
= note: expected associated type `<impl Bar as Foo>::Item`
|
||||
found type `i32`
|
||||
= help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32` or calling a method that returns `<impl Bar as Foo>::Item`
|
||||
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
|
||||
help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32`
|
||||
|
|
||||
LL | fn bar() -> impl Bar<Item = i32> {
|
||||
|
|
|
@ -8,10 +8,10 @@ LL | Box::new(async { x } )
|
|||
| may outlive borrowed value `x`
|
||||
|
|
||||
note: async block is returned here
|
||||
--> $DIR/async-borrowck-escaping-block-error.rs:4:20
|
||||
--> $DIR/async-borrowck-escaping-block-error.rs:6:5
|
||||
|
|
||||
LL | fn test_boxed() -> Box<impl std::future::Future<Output = u32>> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | Box::new(async { x } )
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: to force the async block to take ownership of `x` (and any other referenced variables), use the `move` keyword
|
||||
|
|
||||
LL | Box::new(async move { x } )
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
use std::future::Future;
|
||||
|
||||
fn get_future() -> impl Future<Output = ()> {
|
||||
//~^ ERROR `()` is not a future
|
||||
panic!()
|
||||
panic!() //~^ ERROR `()` is not a future
|
||||
}
|
||||
|
||||
async fn foo() {
|
||||
|
|
|
@ -8,13 +8,13 @@ LL | fn get_future() -> impl Future<Output = ()> {
|
|||
= note: () must be a future or must implement `IntoFuture` to be awaited
|
||||
|
||||
error[E0698]: type inside `async fn` body must be known in this context
|
||||
--> $DIR/async-error-span.rs:13:9
|
||||
--> $DIR/async-error-span.rs:12:9
|
||||
|
|
||||
LL | let a;
|
||||
| ^ cannot infer type
|
||||
|
|
||||
note: the type is part of the `async fn` body because of this `await`
|
||||
--> $DIR/async-error-span.rs:14:17
|
||||
--> $DIR/async-error-span.rs:13:17
|
||||
|
|
||||
LL | get_future().await;
|
||||
| ^^^^^^
|
||||
|
|
|
@ -13,9 +13,9 @@ impl Client {
|
|||
async fn get() { }
|
||||
|
||||
pub fn foo() -> impl Future + Send {
|
||||
//~^ ERROR future cannot be sent between threads safely
|
||||
let client = Client(Box::new(true));
|
||||
async move {
|
||||
//~^ ERROR future cannot be sent between threads safely
|
||||
match client.status() {
|
||||
200 => {
|
||||
let _x = get().await;
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
error: future cannot be sent between threads safely
|
||||
--> $DIR/issue-64130-4-async-move.rs:15:17
|
||||
--> $DIR/issue-64130-4-async-move.rs:17:5
|
||||
|
|
||||
LL | pub fn foo() -> impl Future + Send {
|
||||
| ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
|
||||
LL | / async move {
|
||||
LL | |
|
||||
LL | | match client.status() {
|
||||
LL | | 200 => {
|
||||
... |
|
||||
LL | | }
|
||||
LL | | }
|
||||
| |_____^ future created by async block is not `Send`
|
||||
|
|
||||
= help: the trait `Sync` is not implemented for `(dyn Any + Send + 'static)`
|
||||
note: future is not `Send` as this value is used across an await
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
use std::future::Future;
|
||||
fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
|
||||
//~^ Error future cannot be sent between threads safely
|
||||
async { (ty, ty1) }
|
||||
//~^ Error future cannot be sent between threads safely
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
error: future cannot be sent between threads safely
|
||||
--> $DIR/issue-70818.rs:4:38
|
||||
--> $DIR/issue-70818.rs:5:5
|
||||
|
|
||||
LL | fn foo<T: Send, U>(ty: T, ty1: U) -> impl Future<Output = (T, U)> + Send {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
|
||||
LL | async { (ty, ty1) }
|
||||
| ^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
|
||||
|
|
||||
note: captured value is not `Send`
|
||||
--> $DIR/issue-70818.rs:6:18
|
||||
--> $DIR/issue-70818.rs:5:18
|
||||
|
|
||||
LL | async { (ty, ty1) }
|
||||
| ^^^ has type `U` which is not `Send`
|
||||
|
|
|
@ -8,8 +8,8 @@ async fn baz<T>(_c: impl FnMut() -> T) where T: Future<Output=()> {
|
|||
}
|
||||
|
||||
fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
|
||||
//~^ ERROR: future cannot be sent between threads safely
|
||||
async move {
|
||||
//~^ ERROR: future cannot be sent between threads safely
|
||||
baz(|| async{
|
||||
foo(tx.clone());
|
||||
}).await;
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
error: future cannot be sent between threads safely
|
||||
--> $DIR/issue-70935-complex-spans.rs:10:45
|
||||
--> $DIR/issue-70935-complex-spans.rs:11:5
|
||||
|
|
||||
LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
|
||||
| ^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
|
||||
LL | / async move {
|
||||
LL | |
|
||||
LL | | baz(|| async{
|
||||
LL | | foo(tx.clone());
|
||||
LL | | }).await;
|
||||
LL | | }
|
||||
| |_____^ future created by async block is not `Send`
|
||||
|
|
||||
= help: the trait `Sync` is not implemented for `Sender<i32>`
|
||||
note: future is not `Send` as this value is used across an await
|
||||
|
|
|
@ -17,14 +17,13 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
|
|||
--> $DIR/ret-impl-trait-one.rs:16:65
|
||||
|
|
||||
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
|
||||
| -- ^^^^^^^^^^^^^^
|
||||
| |
|
||||
| hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
|
||||
note: hidden type `(&'a u8, &'<empty> u8)` captures lifetime smaller than the function body
|
||||
--> $DIR/ret-impl-trait-one.rs:16:65
|
||||
|
|
||||
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
|
||||
| ++++
|
||||
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -1,24 +1,26 @@
|
|||
error[E0623]: lifetime mismatch
|
||||
--> $DIR/ret-impl-trait-one.rs:10:65
|
||||
--> $DIR/ret-impl-trait-one.rs:10:85
|
||||
|
|
||||
LL | async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
|
||||
| ------ ^^^^^^^^^^^^^^^^^^^
|
||||
| | |
|
||||
| | ...but data from `a` is returned here
|
||||
| this parameter and the return type are declared with different lifetimes...
|
||||
LL | async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
|
||||
| ______________________________________________________------_____-------------------_^
|
||||
| | |
|
||||
| | this parameter and the return type are declared with different lifetimes...
|
||||
LL | |
|
||||
LL | | (a, b)
|
||||
LL | | }
|
||||
| |_^ ...but data from `a` is returned here
|
||||
|
||||
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
|
||||
--> $DIR/ret-impl-trait-one.rs:16:65
|
||||
|
|
||||
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
|
||||
| -- ^^^^^^^^^^^^^^
|
||||
| |
|
||||
| hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
help: to declare that the `impl Trait` captures `'b`, you can add an explicit `'b` lifetime bound
|
||||
note: hidden type `(&'a u8, &'<empty> u8)` captures lifetime smaller than the function body
|
||||
--> $DIR/ret-impl-trait-one.rs:16:65
|
||||
|
|
||||
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
|
||||
| ++++
|
||||
LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -3,3 +3,4 @@
|
|||
|
||||
pub const async fn x() {}
|
||||
//~^ ERROR functions cannot be both `const` and `async`
|
||||
//~| ERROR cycle detected
|
||||
|
|
|
@ -7,5 +7,36 @@ LL | pub const async fn x() {}
|
|||
| | `async` because of this
|
||||
| `const` because of this
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0391]: cycle detected when computing type of `x::{opaque#0}`
|
||||
--> $DIR/no-const-async.rs:4:24
|
||||
|
|
||||
LL | pub const async fn x() {}
|
||||
| ^
|
||||
|
|
||||
note: ...which requires borrow-checking `x`...
|
||||
--> $DIR/no-const-async.rs:4:1
|
||||
|
|
||||
LL | pub const async fn x() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: ...which requires processing `x`...
|
||||
--> $DIR/no-const-async.rs:4:1
|
||||
|
|
||||
LL | pub const async fn x() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: ...which requires const checking `x`...
|
||||
--> $DIR/no-const-async.rs:4:1
|
||||
|
|
||||
LL | pub const async fn x() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: ...which requires computing whether `impl core::future::future::Future<Output = ()>` is freeze...
|
||||
= note: ...which requires evaluating trait selection obligation `impl core::future::future::Future<Output = ()>: core::marker::Freeze`...
|
||||
= note: ...which again requires computing type of `x::{opaque#0}`, completing the cycle
|
||||
note: cycle used when checking item types in top-level module
|
||||
--> $DIR/no-const-async.rs:4:1
|
||||
|
|
||||
LL | pub const async fn x() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0391`.
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
// Test that impl trait does not allow creating recursive types that are
|
||||
// otherwise forbidden when using `async` and `await`.
|
||||
|
||||
async fn recursive_async_function() -> () { //~ ERROR
|
||||
async fn recursive_async_function() -> () {
|
||||
//~^ ERROR recursion in an `async fn` requires boxing
|
||||
recursive_async_function().await;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ async fn dummy() {}
|
|||
async fn suggest_await_in_async_fn_return() {
|
||||
dummy()
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
//~| HELP consider using a semicolon here
|
||||
//~| HELP consider `await`ing on the `Future`
|
||||
//~| SUGGESTION .await
|
||||
}
|
||||
|
|
|
@ -33,13 +33,9 @@ help: consider `await`ing on the `Future`
|
|||
|
|
||||
LL | dummy().await
|
||||
| ++++++
|
||||
help: consider using a semicolon here
|
||||
|
|
||||
LL | dummy();
|
||||
| +
|
||||
|
||||
error[E0308]: `if` and `else` have incompatible types
|
||||
--> $DIR/suggest-missing-await.rs:35:9
|
||||
--> $DIR/suggest-missing-await.rs:34:9
|
||||
|
|
||||
LL | let _x = if true {
|
||||
| ______________-
|
||||
|
@ -53,15 +49,20 @@ LL | |
|
|||
LL | | };
|
||||
| |_____- `if` and `else` have incompatible types
|
||||
|
|
||||
= note: expected type `impl Future<Output = ()>`
|
||||
found unit type `()`
|
||||
note: while checking the return type of the `async fn`
|
||||
--> $DIR/suggest-missing-await.rs:18:18
|
||||
|
|
||||
LL | async fn dummy() {}
|
||||
| ^ checked the `Output` of this `async fn`, expected opaque type
|
||||
= note: expected opaque type `impl Future<Output = ()>`
|
||||
found unit type `()`
|
||||
help: consider `await`ing on the `Future`
|
||||
|
|
||||
LL | dummy().await
|
||||
| ++++++
|
||||
|
||||
error[E0308]: `match` arms have incompatible types
|
||||
--> $DIR/suggest-missing-await.rs:45:14
|
||||
--> $DIR/suggest-missing-await.rs:44:14
|
||||
|
|
||||
LL | let _x = match 0usize {
|
||||
| ______________-
|
||||
|
@ -89,7 +90,7 @@ LL ~ 1 => dummy().await,
|
|||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-missing-await.rs:53:9
|
||||
--> $DIR/suggest-missing-await.rs:52:9
|
||||
|
|
||||
LL | () => {}
|
||||
| ^^ expected opaque type, found `()`
|
||||
|
@ -107,13 +108,13 @@ LL | let _x = match dummy().await {
|
|||
| ++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-missing-await.rs:67:9
|
||||
--> $DIR/suggest-missing-await.rs:66:9
|
||||
|
|
||||
LL | Ok(_) => {}
|
||||
| ^^^^^ expected opaque type, found enum `Result`
|
||||
|
|
||||
note: while checking the return type of the `async fn`
|
||||
--> $DIR/suggest-missing-await.rs:57:28
|
||||
--> $DIR/suggest-missing-await.rs:56:28
|
||||
|
|
||||
LL | async fn dummy_result() -> Result<(), ()> {
|
||||
| ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type
|
||||
|
@ -125,13 +126,13 @@ LL | match dummy_result().await {
|
|||
| ++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/suggest-missing-await.rs:69:9
|
||||
--> $DIR/suggest-missing-await.rs:68:9
|
||||
|
|
||||
LL | Err(_) => {}
|
||||
| ^^^^^^ expected opaque type, found enum `Result`
|
||||
|
|
||||
note: while checking the return type of the `async fn`
|
||||
--> $DIR/suggest-missing-await.rs:57:28
|
||||
--> $DIR/suggest-missing-await.rs:56:28
|
||||
|
|
||||
LL | async fn dummy_result() -> Result<(), ()> {
|
||||
| ^^^^^^^^^^^^^^ checked the `Output` of this `async fn`, expected opaque type
|
||||
|
|
|
@ -18,5 +18,5 @@ fn main() {
|
|||
// this is an `*mut fmt::Debug` in practice
|
||||
let mut b_raw = Box::into_raw(b);
|
||||
// ... and they should not be mixable
|
||||
b_raw = f_raw as *mut _; //~ ERROR is invalid
|
||||
b_raw = f_raw as *mut _; //~ ERROR mismatched types
|
||||
}
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
error[E0606]: casting `*mut impl Debug + ?Sized` as `*mut impl Debug + ?Sized` is invalid
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/casts-differing-anon.rs:21:13
|
||||
|
|
||||
LL | fn foo() -> Box<impl fmt::Debug+?Sized> {
|
||||
| ---------------------- the found opaque type
|
||||
...
|
||||
LL | fn bar() -> Box<impl fmt::Debug+?Sized> {
|
||||
| ---------------------- the expected opaque type
|
||||
...
|
||||
LL | b_raw = f_raw as *mut _;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
| ^^^^^ expected opaque type, found a different opaque type
|
||||
|
|
||||
= note: vtable kinds may not match
|
||||
= note: expected opaque type `impl Debug + ?Sized` (opaque type at <$DIR/casts-differing-anon.rs:7:17>)
|
||||
found opaque type `impl Debug + ?Sized` (opaque type at <$DIR/casts-differing-anon.rs:3:17>)
|
||||
= note: distinct uses of `impl Trait` result in different opaque types
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0606`.
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
|
|
@ -8,10 +8,10 @@ LL | println!("{:?}", p);
|
|||
| - `p` is borrowed here
|
||||
|
|
||||
note: closure is returned here
|
||||
--> $DIR/borrowck-4.rs:8:14
|
||||
--> $DIR/borrowck-4.rs:15:5
|
||||
|
|
||||
LL | fn foo () -> impl FnMut()->() {
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
LL | c
|
||||
| ^
|
||||
help: to force the closure to take ownership of `p` (and any other referenced variables), use the `move` keyword
|
||||
|
|
||||
LL | let mut c = move || {
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
error[E0277]: `()` is not an iterator
|
||||
--> $DIR/conservative_impl_trait.rs:3:33
|
||||
--> $DIR/conservative_impl_trait.rs:3:60
|
||||
|
|
||||
LL | fn will_ice(something: &u32) -> impl Iterator<Item = &u32> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
|
||||
LL | fn will_ice(something: &u32) -> impl Iterator<Item = &u32> {
|
||||
| ____________________________________________________________^
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_^ `()` is not an iterator
|
||||
|
|
||||
= help: the trait `Iterator` is not implemented for `()`
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@ trait Trait {}
|
|||
impl<const N: u32> Trait for Uwu<N> {}
|
||||
|
||||
fn rawr() -> impl Trait {
|
||||
//~^ error: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
|
||||
Uwu::<10, 12>
|
||||
//~^ error: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
|
||||
}
|
||||
|
||||
trait Traitor<const N: u8 = 1, const M: u8 = N> { }
|
||||
|
@ -15,13 +15,13 @@ impl Traitor<1, 2> for u64 {}
|
|||
|
||||
|
||||
fn uwu<const N: u8>() -> impl Traitor<N> {
|
||||
//~^ error: the trait bound `u32: Traitor<N, N>` is not satisfied
|
||||
1_u32
|
||||
//~^ error: the trait bound `u32: Traitor<N, N>` is not satisfied
|
||||
}
|
||||
|
||||
fn owo() -> impl Traitor {
|
||||
//~^ error: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
|
||||
1_u64
|
||||
//~^ error: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
error[E0277]: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
|
||||
--> $DIR/rp_impl_trait_fail.rs:6:14
|
||||
--> $DIR/rp_impl_trait_fail.rs:7:5
|
||||
|
|
||||
LL | fn rawr() -> impl Trait {
|
||||
| ^^^^^^^^^^ the trait `Trait` is not implemented for `Uwu<10_u32, 12_u32>`
|
||||
LL | Uwu::<10, 12>
|
||||
| ^^^^^^^^^^^^^ the trait `Trait` is not implemented for `Uwu<10_u32, 12_u32>`
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
<Uwu<N> as Trait>
|
||||
|
||||
error[E0277]: the trait bound `u32: Traitor<N, N>` is not satisfied
|
||||
--> $DIR/rp_impl_trait_fail.rs:17:26
|
||||
--> $DIR/rp_impl_trait_fail.rs:18:5
|
||||
|
|
||||
LL | fn uwu<const N: u8>() -> impl Traitor<N> {
|
||||
| ^^^^^^^^^^^^^^^ the trait `Traitor<N, N>` is not implemented for `u32`
|
||||
LL | 1_u32
|
||||
| ^^^^^ the trait `Traitor<N, N>` is not implemented for `u32`
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
<u32 as Traitor<N, 2_u8>>
|
||||
|
||||
error[E0277]: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
|
||||
--> $DIR/rp_impl_trait_fail.rs:22:13
|
||||
--> $DIR/rp_impl_trait_fail.rs:23:5
|
||||
|
|
||||
LL | fn owo() -> impl Traitor {
|
||||
| ^^^^^^^^^^^^ the trait `Traitor<1_u8, 1_u8>` is not implemented for `u64`
|
||||
LL | 1_u64
|
||||
| ^^^^^ the trait `Traitor<1_u8, 1_u8>` is not implemented for `u64`
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
<u64 as Traitor<1_u8, 2_u8>>
|
||||
|
|
|
@ -4,11 +4,9 @@
|
|||
//~^^^ ERROR `main` function not found in crate
|
||||
pub mod foo {
|
||||
type MainFn = impl Fn();
|
||||
//~^ ERROR could not find defining uses
|
||||
|
||||
fn bar() {}
|
||||
pub const BAR: MainFn = bar;
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
}
|
||||
|
||||
use foo::BAR as main;
|
||||
|
|
|
@ -12,25 +12,6 @@ LL | | use foo::BAR as main;
|
|||
| |
|
||||
| non-function item at `crate::main` is found
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/imported_main_const_fn_item_type_forbidden.rs:10:29
|
||||
|
|
||||
LL | type MainFn = impl Fn();
|
||||
| --------- the expected opaque type
|
||||
...
|
||||
LL | pub const BAR: MainFn = bar;
|
||||
| ^^^ expected opaque type, found fn item
|
||||
|
|
||||
= note: expected opaque type `impl Fn()`
|
||||
found fn item `fn() {bar}`
|
||||
error: aborting due to previous error
|
||||
|
||||
error: could not find defining uses
|
||||
--> $DIR/imported_main_const_fn_item_type_forbidden.rs:6:19
|
||||
|
|
||||
LL | type MainFn = impl Fn();
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0308, E0601.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
||||
For more information about this error, try `rustc --explain E0601`.
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
// ignore-compare-mode-chalk
|
||||
// check-pass
|
||||
#![feature(type_alias_impl_trait)]
|
||||
use std::fmt::Debug;
|
||||
|
||||
type Foo = impl Debug;
|
||||
//~^ ERROR could not find defining uses
|
||||
|
||||
struct Bar(Foo);
|
||||
fn define() -> Bar {
|
||||
Bar(42) //~ ERROR mismatched types
|
||||
Bar(42)
|
||||
}
|
||||
|
||||
type Foo2 = impl Debug;
|
||||
|
@ -17,21 +17,18 @@ fn define2() {
|
|||
}
|
||||
|
||||
type Foo3 = impl Debug;
|
||||
//~^ ERROR could not find defining uses
|
||||
|
||||
fn define3(x: Foo3) {
|
||||
let y: i32 = x; //~ ERROR mismatched types
|
||||
let y: i32 = x;
|
||||
}
|
||||
fn define3_1() {
|
||||
define3(42) //~ ERROR mismatched types
|
||||
define3(42)
|
||||
}
|
||||
|
||||
type Foo4 = impl Debug;
|
||||
//~^ ERROR could not find defining uses
|
||||
|
||||
fn define4() {
|
||||
let y: Foo4 = 42;
|
||||
//~^ ERROR mismatched types [E0308]
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/feature-gate-type_alias_impl_trait.rs:10:9
|
||||
|
|
||||
LL | type Foo = impl Debug;
|
||||
| ---------- the expected opaque type
|
||||
...
|
||||
LL | Bar(42)
|
||||
| ^^ expected opaque type, found integer
|
||||
|
|
||||
= note: expected opaque type `impl Debug`
|
||||
found type `{integer}`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/feature-gate-type_alias_impl_trait.rs:23:18
|
||||
|
|
||||
LL | type Foo3 = impl Debug;
|
||||
| ---------- the found opaque type
|
||||
...
|
||||
LL | let y: i32 = x;
|
||||
| --- ^ expected `i32`, found opaque type
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected type `i32`
|
||||
found opaque type `impl Debug`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/feature-gate-type_alias_impl_trait.rs:26:13
|
||||
|
|
||||
LL | type Foo3 = impl Debug;
|
||||
| ---------- the expected opaque type
|
||||
...
|
||||
LL | define3(42)
|
||||
| ^^ expected opaque type, found integer
|
||||
|
|
||||
= note: expected opaque type `impl Debug`
|
||||
found type `{integer}`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/feature-gate-type_alias_impl_trait.rs:33:19
|
||||
|
|
||||
LL | type Foo4 = impl Debug;
|
||||
| ---------- the expected opaque type
|
||||
...
|
||||
LL | let y: Foo4 = 42;
|
||||
| ---- ^^ expected opaque type, found integer
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected opaque type `impl Debug`
|
||||
found type `{integer}`
|
||||
|
||||
error: could not find defining uses
|
||||
--> $DIR/feature-gate-type_alias_impl_trait.rs:5:12
|
||||
|
|
||||
LL | type Foo = impl Debug;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: could not find defining uses
|
||||
--> $DIR/feature-gate-type_alias_impl_trait.rs:19:13
|
||||
|
|
||||
LL | type Foo3 = impl Debug;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: could not find defining uses
|
||||
--> $DIR/feature-gate-type_alias_impl_trait.rs:29:13
|
||||
|
|
||||
LL | type Foo4 = impl Debug;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
|
@ -6,10 +6,10 @@
|
|||
use std::ops::Generator;
|
||||
|
||||
fn foo(bar: bool) -> impl Generator<(bool,)> {
|
||||
//~^ ERROR: type mismatch in generator arguments [E0631]
|
||||
//~| NOTE: expected signature of `fn((bool,)) -> _`
|
||||
|bar| {
|
||||
//~^ NOTE: found signature of `fn(bool) -> _`
|
||||
//~| ERROR: type mismatch in generator arguments [E0631]
|
||||
//~| NOTE: expected signature of `fn((bool,)) -> _`
|
||||
if bar {
|
||||
yield bar;
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue