Move late-bound arg type checks to resolve_bound_vars

This commit is contained in:
Michael Goulet 2023-02-18 03:28:43 +00:00
parent fded2e95ab
commit cec7835d7a
10 changed files with 171 additions and 87 deletions

View File

@ -252,6 +252,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// (*) -- not late-bound, won't change // (*) -- not late-bound, won't change
} }
Some(rbv::ResolvedArg::Error(_)) => {
bug!("only ty/ct should resolve as ResolvedArg::Error")
}
None => { None => {
self.re_infer(def, lifetime.ident.span).unwrap_or_else(|| { self.re_infer(def, lifetime.ident.span).unwrap_or_else(|| {
debug!(?lifetime, "unelided lifetime in signature"); debug!(?lifetime, "unelided lifetime in signature");
@ -2689,6 +2693,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let index = generics.param_def_id_to_index[&def_id.to_def_id()]; let index = generics.param_def_id_to_index[&def_id.to_def_id()];
tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id)) tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id))
} }
Some(rbv::ResolvedArg::Error(guar)) => tcx.ty_error_with_guaranteed(guar),
arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"), arg => bug!("unexpected bound var resolution for {hir_id:?}: {arg:?}"),
} }
} }
@ -2893,22 +2898,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
hir::TyKind::BareFn(bf) => { hir::TyKind::BareFn(bf) => {
require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span); require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span);
let fn_ptr_ty = tcx.mk_fn_ptr(self.ty_of_fn( tcx.mk_fn_ptr(self.ty_of_fn(
ast_ty.hir_id, ast_ty.hir_id,
bf.unsafety, bf.unsafety,
bf.abi, bf.abi,
bf.decl, bf.decl,
None, None,
Some(ast_ty), Some(ast_ty),
)); ))
if let Some(guar) =
deny_non_region_late_bound(tcx, bf.generic_params, "function pointer")
{
tcx.ty_error_with_guaranteed(guar)
} else {
fn_ptr_ty
}
} }
hir::TyKind::TraitObject(bounds, lifetime, repr) => { hir::TyKind::TraitObject(bounds, lifetime, repr) => {
self.maybe_lint_bare_trait(ast_ty, in_path); self.maybe_lint_bare_trait(ast_ty, in_path);
@ -2917,21 +2914,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
TraitObjectSyntax::DynStar => ty::DynStar, TraitObjectSyntax::DynStar => ty::DynStar,
}; };
let object_ty = self.conv_object_ty_poly_trait_ref( self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr)
ast_ty.span,
bounds,
lifetime,
borrowed,
repr,
);
if let Some(guar) = bounds.iter().find_map(|trait_ref| {
deny_non_region_late_bound(tcx, trait_ref.bound_generic_params, "trait object")
}) {
tcx.ty_error_with_guaranteed(guar)
} else {
object_ty
}
} }
hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
debug!(?maybe_qself, ?path); debug!(?maybe_qself, ?path);
@ -3392,24 +3375,3 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
} }
} }
} }
fn deny_non_region_late_bound(
tcx: TyCtxt<'_>,
params: &[hir::GenericParam<'_>],
where_: &str,
) -> Option<ErrorGuaranteed> {
params.iter().find_map(|bad_param| {
let what = match bad_param.kind {
hir::GenericParamKind::Type { .. } => "type",
hir::GenericParamKind::Const { .. } => "const",
hir::GenericParamKind::Lifetime { .. } => return None,
};
let mut diag = tcx.sess.struct_span_err(
bad_param.span,
format!("late-bound {what} parameter not allowed on {where_} types"),
);
Some(if tcx.features().non_lifetime_binders { diag.emit() } else { diag.delay_as_bug() })
})
}

View File

@ -398,7 +398,12 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {} Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {}
Some(rbv::ResolvedArg::LateBound(debruijn, _, _)) Some(rbv::ResolvedArg::LateBound(debruijn, _, _))
if debruijn < self.outer_index => {} if debruijn < self.outer_index => {}
Some(rbv::ResolvedArg::LateBound(..) | rbv::ResolvedArg::Free(..)) | None => { Some(
rbv::ResolvedArg::LateBound(..)
| rbv::ResolvedArg::Free(..)
| rbv::ResolvedArg::Error(_),
)
| None => {
self.has_late_bound_regions = Some(lt.ident.span); self.has_late_bound_regions = Some(lt.ident.span);
} }
} }

View File

@ -50,7 +50,7 @@ impl RegionExt for ResolvedArg {
fn id(&self) -> Option<DefId> { fn id(&self) -> Option<DefId> {
match *self { match *self {
ResolvedArg::StaticLifetime => None, ResolvedArg::StaticLifetime | ResolvedArg::Error(_) => None,
ResolvedArg::EarlyBound(id) ResolvedArg::EarlyBound(id)
| ResolvedArg::LateBound(_, _, id) | ResolvedArg::LateBound(_, _, id)
@ -336,7 +336,57 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
} }
} }
} }
fn visit_poly_trait_ref_inner(
&mut self,
trait_ref: &'tcx hir::PolyTraitRef<'tcx>,
non_lifetime_binder_allowed: NonLifetimeBinderAllowed,
) {
debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref);
let (mut binders, scope_type) = self.poly_trait_ref_binder_info();
let initial_bound_vars = binders.len() as u32;
let mut bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = FxIndexMap::default();
let binders_iter =
trait_ref.bound_generic_params.iter().enumerate().map(|(late_bound_idx, param)| {
let pair = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param);
let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
bound_vars.insert(pair.0, pair.1);
r
});
binders.extend(binders_iter);
if let NonLifetimeBinderAllowed::Deny(where_) = non_lifetime_binder_allowed {
deny_non_region_late_bound(self.tcx, &mut bound_vars, where_);
}
debug!(?binders);
self.record_late_bound_vars(trait_ref.trait_ref.hir_ref_id, binders);
// Always introduce a scope here, even if this is in a where clause and
// we introduced the binders around the bounded Ty. In that case, we
// just reuse the concatenation functionality also present in nested trait
// refs.
let scope = Scope::Binder {
hir_id: trait_ref.trait_ref.hir_ref_id,
bound_vars,
s: self.scope,
scope_type,
where_bound_origin: None,
};
self.with(scope, |this| {
walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
this.visit_trait_ref(&trait_ref.trait_ref);
});
}
} }
enum NonLifetimeBinderAllowed {
Deny(&'static str),
Allow,
}
impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
type NestedFilter = nested_filter::OnlyBodies; type NestedFilter = nested_filter::OnlyBodies;
@ -400,7 +450,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
} }
} }
let (bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) = let (mut bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) =
bound_generic_params bound_generic_params
.iter() .iter()
.enumerate() .enumerate()
@ -411,6 +461,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}) })
.unzip(); .unzip();
deny_non_region_late_bound(self.tcx, &mut bound_vars, "closures");
self.record_late_bound_vars(e.hir_id, binders); self.record_late_bound_vars(e.hir_id, binders);
let scope = Scope::Binder { let scope = Scope::Binder {
hir_id: e.hir_id, hir_id: e.hir_id,
@ -567,7 +619,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
match ty.kind { match ty.kind {
hir::TyKind::BareFn(c) => { hir::TyKind::BareFn(c) => {
let (bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) = c let (mut bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) = c
.generic_params .generic_params
.iter() .iter()
.enumerate() .enumerate()
@ -577,6 +629,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
(pair, r) (pair, r)
}) })
.unzip(); .unzip();
deny_non_region_late_bound(self.tcx, &mut bound_vars, "function pointer types");
self.record_late_bound_vars(ty.hir_id, binders); self.record_late_bound_vars(ty.hir_id, binders);
let scope = Scope::Binder { let scope = Scope::Binder {
hir_id: ty.hir_id, hir_id: ty.hir_id,
@ -596,7 +651,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
let scope = Scope::TraitRefBoundary { s: self.scope }; let scope = Scope::TraitRefBoundary { s: self.scope };
self.with(scope, |this| { self.with(scope, |this| {
for bound in bounds { for bound in bounds {
this.visit_poly_trait_ref(bound); this.visit_poly_trait_ref_inner(
bound,
NonLifetimeBinderAllowed::Deny("trait object types"),
);
} }
}); });
match lifetime.res { match lifetime.res {
@ -967,39 +1025,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
} }
fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) { fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) {
debug!("visit_poly_trait_ref(trait_ref={:?})", trait_ref); self.visit_poly_trait_ref_inner(trait_ref, NonLifetimeBinderAllowed::Allow);
let (mut binders, scope_type) = self.poly_trait_ref_binder_info();
let initial_bound_vars = binders.len() as u32;
let mut bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = FxIndexMap::default();
let binders_iter =
trait_ref.bound_generic_params.iter().enumerate().map(|(late_bound_idx, param)| {
let pair = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param);
let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
bound_vars.insert(pair.0, pair.1);
r
});
binders.extend(binders_iter);
debug!(?binders);
self.record_late_bound_vars(trait_ref.trait_ref.hir_ref_id, binders);
// Always introduce a scope here, even if this is in a where clause and
// we introduced the binders around the bounded Ty. In that case, we
// just reuse the concatenation functionality also present in nested trait
// refs.
let scope = Scope::Binder {
hir_id: trait_ref.trait_ref.hir_ref_id,
bound_vars,
s: self.scope,
scope_type,
where_bound_origin: None,
};
self.with(scope, |this| {
walk_list!(this, visit_generic_param, trait_ref.bound_generic_params);
this.visit_trait_ref(&trait_ref.trait_ref);
});
} }
} }
@ -1364,7 +1390,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
return; return;
} }
span_bug!(self.tcx.hir().span(hir_id), "could not resolve {param_def_id:?}",); self.tcx
.sess
.delay_span_bug(self.tcx.hir().span(hir_id), "could not resolve {param_def_id:?}");
} }
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
@ -1915,3 +1943,37 @@ fn is_late_bound_map(
} }
} }
} }
pub fn deny_non_region_late_bound(
tcx: TyCtxt<'_>,
bound_vars: &mut FxIndexMap<LocalDefId, ResolvedArg>,
where_: &str,
) {
let mut first = true;
for (var, arg) in bound_vars {
let Node::GenericParam(param) = tcx.hir().get_by_def_id(*var) else {
bug!();
};
let what = match param.kind {
hir::GenericParamKind::Type { .. } => "type",
hir::GenericParamKind::Const { .. } => "const",
hir::GenericParamKind::Lifetime { .. } => continue,
};
let mut diag = tcx.sess.struct_span_err(
param.span,
format!("late-bound {what} parameter not allowed on {where_}"),
);
let guar = if tcx.features().non_lifetime_binders && first {
diag.emit()
} else {
diag.delay_as_bug()
};
first = false;
*arg = ResolvedArg::Error(guar);
}
}

View File

@ -134,7 +134,8 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
rbv::ResolvedArg::StaticLifetime rbv::ResolvedArg::StaticLifetime
| rbv::ResolvedArg::Free(_, _) | rbv::ResolvedArg::Free(_, _)
| rbv::ResolvedArg::EarlyBound(_) | rbv::ResolvedArg::EarlyBound(_)
| rbv::ResolvedArg::LateBound(_, _, _), | rbv::ResolvedArg::LateBound(_, _, _)
| rbv::ResolvedArg::Error(_),
) )
| None, | None,
_, _,
@ -211,7 +212,8 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
rbv::ResolvedArg::StaticLifetime rbv::ResolvedArg::StaticLifetime
| rbv::ResolvedArg::EarlyBound(_) | rbv::ResolvedArg::EarlyBound(_)
| rbv::ResolvedArg::LateBound(_, _, _) | rbv::ResolvedArg::LateBound(_, _, _)
| rbv::ResolvedArg::Free(_, _), | rbv::ResolvedArg::Free(_, _)
| rbv::ResolvedArg::Error(_),
) )
| None, | None,
_, _,

View File

@ -3,6 +3,7 @@
use crate::ty; use crate::ty;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::{ItemLocalId, OwnerId}; use rustc_hir::{ItemLocalId, OwnerId};
use rustc_macros::HashStable; use rustc_macros::HashStable;
@ -13,6 +14,7 @@ pub enum ResolvedArg {
EarlyBound(/* decl */ DefId), EarlyBound(/* decl */ DefId),
LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* decl */ DefId), LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* decl */ DefId),
Free(DefId, /* lifetime decl */ DefId), Free(DefId, /* lifetime decl */ DefId),
Error(ErrorGuaranteed),
} }
/// A set containing, at most, one known element. /// A set containing, at most, one known element.

View File

@ -149,6 +149,9 @@ impl<'tcx> Const<'tcx> {
ty::ConstKind::Bound(debruijn, ty::BoundVar::from_u32(index)), ty::ConstKind::Bound(debruijn, ty::BoundVar::from_u32(index)),
ty, ty,
)), )),
Some(rbv::ResolvedArg::Error(guar)) => {
Some(tcx.const_error_with_guaranteed(ty, guar))
}
arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", expr.hir_id), arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", expr.hir_id),
} }
} }

View File

@ -0,0 +1,7 @@
#![feature(closure_lifetime_binder, non_lifetime_binders)]
//~^ WARN is incomplete and may not be safe to use
fn main() {
for<T> || -> () {};
//~^ ERROR late-bound type parameter not allowed on closures
}

View File

@ -0,0 +1,17 @@
warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/type-bound-2.rs:1:37
|
LL | #![feature(closure_lifetime_binder, non_lifetime_binders)]
| ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
= note: `#[warn(incomplete_features)]` on by default
error: late-bound type parameter not allowed on closures
--> $DIR/type-bound-2.rs:5:9
|
LL | for<T> || -> () {};
| ^
error: aborting due to previous error; 1 warning emitted

View File

@ -0,0 +1,7 @@
#![feature(closure_lifetime_binder, non_lifetime_binders)]
//~^ WARN is incomplete and may not be safe to use
fn main() {
for<T> || -> T {};
//~^ ERROR late-bound type parameter not allowed on closures
}

View File

@ -0,0 +1,17 @@
warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/type-bound.rs:1:37
|
LL | #![feature(closure_lifetime_binder, non_lifetime_binders)]
| ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
= note: `#[warn(incomplete_features)]` on by default
error: late-bound type parameter not allowed on closures
--> $DIR/type-bound.rs:5:9
|
LL | for<T> || -> T {};
| ^
error: aborting due to previous error; 1 warning emitted