Check that TAIT generics are fully generic in mir typeck instead of wf-check, as wf-check can by definition only check TAIT in return position and not account for TAITs defined in the body of the function
This commit is contained in:
parent
15d9ba0133
commit
6067eadb65
33 changed files with 433 additions and 272 deletions
|
@ -1,5 +1,9 @@
|
|||
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};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::opaque_types::InferCtxtExt;
|
||||
|
@ -50,13 +54,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
pub(crate) fn infer_opaque_types(
|
||||
&self,
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
|
||||
opaque_ty_decls: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
|
||||
span: Span,
|
||||
) -> VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>> {
|
||||
opaque_ty_decls
|
||||
.into_iter()
|
||||
.map(|(opaque_type_key, concrete_type)| {
|
||||
.filter_map(|(opaque_type_key, decl)| {
|
||||
let substs = opaque_type_key.substs;
|
||||
let concrete_type = decl.concrete_ty;
|
||||
debug!(?concrete_type, ?substs);
|
||||
|
||||
let mut subst_regions = vec![self.universal_regions.fr_static];
|
||||
|
@ -94,7 +99,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
universal_concrete_type,
|
||||
span,
|
||||
);
|
||||
(opaque_type_key, remapped_type)
|
||||
|
||||
check_opaque_type_parameter_valid(
|
||||
infcx.tcx,
|
||||
opaque_type_key,
|
||||
OpaqueTypeDecl { concrete_ty: remapped_type, ..decl },
|
||||
)
|
||||
.then_some((opaque_type_key, remapped_type))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
@ -119,3 +130,95 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn check_opaque_type_parameter_valid(
|
||||
tcx: TyCtxt<'_>,
|
||||
opaque_type_key: OpaqueTypeKey<'_>,
|
||||
decl: OpaqueTypeDecl<'_>,
|
||||
) -> bool {
|
||||
match decl.origin {
|
||||
// No need to check return position impl trait (RPIT)
|
||||
// because for type and const parameters they are correct
|
||||
// by construction: we convert
|
||||
//
|
||||
// fn foo<P0..Pn>() -> impl Trait
|
||||
//
|
||||
// into
|
||||
//
|
||||
// type Foo<P0...Pn>
|
||||
// fn foo<P0..Pn>() -> Foo<P0...Pn>.
|
||||
//
|
||||
// For lifetime parameters we convert
|
||||
//
|
||||
// fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
|
||||
//
|
||||
// into
|
||||
//
|
||||
// type foo::<'p0..'pn>::Foo<'q0..'qm>
|
||||
// fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
|
||||
//
|
||||
// which would error here on all of the `'static` args.
|
||||
OpaqueTyOrigin::FnReturn | OpaqueTyOrigin::AsyncFn => return true,
|
||||
// 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() {
|
||||
let arg_is_param = match arg.unpack() {
|
||||
GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
|
||||
GenericArgKind::Lifetime(ty::ReStatic) => {
|
||||
tcx.sess
|
||||
.struct_span_err(span, "non-defining opaque type use in defining scope")
|
||||
.span_label(
|
||||
tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
|
||||
"cannot use static lifetime; use a bound lifetime \
|
||||
instead or remove the lifetime parameter from the \
|
||||
opaque type",
|
||||
)
|
||||
.emit();
|
||||
return false;
|
||||
}
|
||||
GenericArgKind::Lifetime(lt) => {
|
||||
matches!(lt, ty::ReEarlyBound(_) | ty::ReFree(_))
|
||||
}
|
||||
GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)),
|
||||
};
|
||||
|
||||
if arg_is_param {
|
||||
seen_params.entry(arg).or_default().push(i);
|
||||
} else {
|
||||
// Prevent `fn foo() -> Foo<u32>` from being defining.
|
||||
let opaque_param = opaque_generics.param_at(i, tcx);
|
||||
tcx.sess
|
||||
.struct_span_err(span, "non-defining opaque type use in defining scope")
|
||||
.span_note(
|
||||
tcx.def_span(opaque_param.def_id),
|
||||
&format!(
|
||||
"used non-generic {} `{}` for generic parameter",
|
||||
opaque_param.kind.descr(),
|
||||
arg,
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (_, indices) in seen_params {
|
||||
if indices.len() > 1 {
|
||||
let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
|
||||
let spans: Vec<_> = indices
|
||||
.into_iter()
|
||||
.map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
|
||||
.collect();
|
||||
tcx.sess
|
||||
.struct_span_err(span, "non-defining opaque type use in defining scope")
|
||||
.span_note(spans, &format!("{} used multiple times", descr))
|
||||
.emit();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ 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::{
|
||||
|
@ -193,16 +194,17 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
|||
|
||||
opaque_type_values
|
||||
.into_iter()
|
||||
.filter_map(|(opaque_type_key, decl)| {
|
||||
let mut revealed_ty = infcx.resolve_vars_if_possible(decl.concrete_ty);
|
||||
if revealed_ty.has_infer_types_or_consts() {
|
||||
.filter_map(|(opaque_type_key, mut decl)| {
|
||||
decl.concrete_ty = infcx.resolve_vars_if_possible(decl.concrete_ty);
|
||||
if decl.concrete_ty.has_infer_types_or_consts() {
|
||||
infcx.tcx.sess.delay_span_bug(
|
||||
body.span,
|
||||
&format!("could not resolve {:#?}", revealed_ty.kind()),
|
||||
&format!("could not resolve {:#?}", decl.concrete_ty.kind()),
|
||||
);
|
||||
revealed_ty = infcx.tcx.ty_error();
|
||||
decl.concrete_ty = infcx.tcx.ty_error();
|
||||
}
|
||||
let concrete_is_opaque = if let ty::Opaque(def_id, _) = revealed_ty.kind() {
|
||||
let concrete_is_opaque = if let ty::Opaque(def_id, _) = decl.concrete_ty.kind()
|
||||
{
|
||||
*def_id == opaque_type_key.def_id
|
||||
} else {
|
||||
false
|
||||
|
@ -234,7 +236,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
|
|||
);
|
||||
None
|
||||
} else {
|
||||
Some((opaque_type_key, revealed_ty))
|
||||
Some((opaque_type_key, decl))
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
|
@ -890,7 +892,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>, Ty<'tcx>>,
|
||||
crate opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>,
|
||||
}
|
||||
|
||||
/// A collection of region constraints that must be satisfied for the
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue