Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial implementation of unsafe binder types #130514

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
29 changes: 28 additions & 1 deletion compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1329,6 +1329,7 @@ impl Expr {
| ExprKind::Type(..)
| ExprKind::OffsetOf(..)
| ExprKind::FormatArgs(..)
| ExprKind::UnsafeBinderCast(..)
| ExprKind::MacCall(..) => ExprPrecedence::Mac,
ExprKind::Err(_) | ExprKind::Dummy => ExprPrecedence::Err,
}
Expand Down Expand Up @@ -1455,7 +1456,13 @@ pub enum ExprKind {
/// `'label: for await? pat in iter { block }`
///
/// This is desugared to a combination of `loop` and `match` expressions.
ForLoop { pat: P<Pat>, iter: P<Expr>, body: P<Block>, label: Option<Label>, kind: ForLoopKind },
ForLoop {
pat: P<Pat>,
iter: P<Expr>,
body: P<Block>,
label: Option<Label>,
kind: ForLoopKind,
},
/// Conditionless loop (can be exited with `break`, `continue`, or `return`).
///
/// `'label: loop { block }`
Expand Down Expand Up @@ -1560,6 +1567,8 @@ pub enum ExprKind {
/// A `format_args!()` expression.
FormatArgs(P<FormatArgs>),

UnsafeBinderCast(UnsafeBinderCastKind, P<Expr>, Option<P<Ty>>),

/// Placeholder for an expression that wasn't syntactically well formed in some way.
Err(ErrorGuaranteed),

Expand Down Expand Up @@ -1598,6 +1607,16 @@ impl GenBlockKind {
}
}

/// Whether we're unwrapping or wrapping an unsafe binder
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Encodable, Decodable, HashStable_Generic)]
pub enum UnsafeBinderCastKind {
// e.g. `&i32` -> `unsafe<'a> &'a i32`
Wrap,
// e.g. `unsafe<'a> &'a i32` -> `&i32`
Unwrap,
}

/// The explicit `Self` type in a "qualified path". The actual
/// path, including the trait and the associated item, is stored
/// separately. `position` represents the index of the associated
Expand Down Expand Up @@ -2148,6 +2167,12 @@ pub struct BareFnTy {
pub decl_span: Span,
}

#[derive(Clone, Encodable, Decodable, Debug)]
pub struct UnsafeBinderTy {
pub generic_params: ThinVec<GenericParam>,
pub inner_ty: P<Ty>,
}

/// The various kinds of type recognized by the compiler.
//
// Adding a new variant? Please update `test_ty` in `tests/ui/macros/stringify.rs`.
Expand All @@ -2163,6 +2188,8 @@ pub enum TyKind {
Ref(Option<Lifetime>, MutTy),
/// A bare function (e.g., `fn(usize) -> bool`).
BareFn(P<BareFnTy>),
/// An unsafe existential lifetime binder (e.g., `unsafe<'a> &'a ()`).
UnsafeBinder(P<UnsafeBinderTy>),
/// The never type (`!`).
Never,
/// A tuple (`(A, B, C, D,...)`).
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,11 @@ pub fn walk_ty<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) {
vis.visit_fn_decl(decl);
vis.visit_span(decl_span);
}
TyKind::UnsafeBinder(binder) => {
let UnsafeBinderTy { generic_params, inner_ty } = binder.deref_mut();
generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
vis.visit_ty(inner_ty);
}
TyKind::Tup(tys) => visit_thin_vec(tys, |ty| vis.visit_ty(ty)),
TyKind::Paren(ty) => vis.visit_ty(ty),
TyKind::Pat(ty, pat) => {
Expand Down Expand Up @@ -1615,6 +1620,12 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token
ExprKind::TryBlock(body) => vis.visit_block(body),
ExprKind::Lit(_token) => {}
ExprKind::IncludedBytes(_bytes) => {}
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
vis.visit_expr(expr);
if let Some(ty) = ty {
vis.visit_ty(ty);
}
}
ExprKind::Err(_guar) => {}
ExprKind::Dummy => {}
}
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_ast/src/util/classify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool {
| Underscore
| Yeet(..)
| Yield(..)
| UnsafeBinderCast(..)
| Err(..)
| Dummy => return false,
}
Expand Down Expand Up @@ -232,6 +233,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
| Paren(_)
| Try(_)
| Yeet(None)
| UnsafeBinderCast(..)
| Err(_)
| Dummy => break None,
}
Expand All @@ -251,6 +253,10 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
ty = &mut_ty.ty;
}

ast::TyKind::UnsafeBinder(binder) => {
ty = &binder.inner_ty;
}

ast::TyKind::BareFn(fn_ty) => match &fn_ty.decl.output {
ast::FnRetTy::Default(_) => break None,
ast::FnRetTy::Ty(ret) => ty = ret,
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,10 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
walk_list!(visitor, visit_generic_param, generic_params);
try_visit!(walk_fn_decl(visitor, decl));
}
TyKind::UnsafeBinder(binder) => {
walk_list!(visitor, visit_generic_param, &binder.generic_params);
try_visit!(visitor.visit_ty(&binder.inner_ty));
}
TyKind::Path(maybe_qself, path) => {
try_visit!(walk_qself(visitor, maybe_qself));
try_visit!(visitor.visit_path(path, *id));
Expand Down Expand Up @@ -1183,6 +1187,10 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)),
ExprKind::Lit(_token) => {}
ExprKind::IncludedBytes(_bytes) => {}
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
try_visit!(visitor.visit_expr(expr));
visit_opt!(visitor, visit_ty, ty);
}
ExprKind::Err(_guar) => {}
ExprKind::Dummy => {}
}
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
ExprKind::Err(guar) => hir::ExprKind::Err(*guar),

ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast(
*kind,
self.lower_expr(expr),
ty.as_ref().map(|ty| {
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast))
}),
),

ExprKind::Dummy => {
span_bug!(e.span, "lowered ExprKind::Dummy")
}
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_ast_lowering/src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,12 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
self.insert(ty.span, ty.hir_id, Node::Ty(ty));

self.with_parent(ty.hir_id, |this| {
// FIXME(unsafe_binders): Should we split this out into a separate
// visit function?
if let TyKind::UnsafeBinder(binder) = ty.kind {
this.insert(ty.span, binder.hir_id, Node::UnsafeBinder(binder));
};

intravisit::walk_ty(this, ty);
});
}
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1332,6 +1332,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param_names: self.lower_fn_params_to_names(&f.decl),
}))
}
TyKind::UnsafeBinder(f) => {
let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
hir::TyKind::UnsafeBinder(self.arena.alloc(hir::UnsafeBinderTy {
span: self.lower_span(t.span),
hir_id: self.next_id(),
generic_params,
inner_ty: self.lower_ty(&f.inner_ty, itctx),
}))
}
TyKind::Never => hir::TyKind::Never,
TyKind::Tup(tys) => hir::TyKind::Tup(
self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))),
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_ast_lowering/src/lifetime_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
visit::walk_ty(self, t);
self.current_binders.pop();
}
TyKind::UnsafeBinder(_) => {
self.current_binders.push(t.id);
visit::walk_ty(self, t);
self.current_binders.pop();
}
TyKind::Ref(None, _) => {
self.record_elided_anchor(t.id, t.span);
visit::walk_ty(self, t);
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1190,6 +1190,14 @@ impl<'a> State<'a> {
ast::TyKind::BareFn(f) => {
self.print_ty_fn(f.ext, f.safety, &f.decl, None, &f.generic_params);
}
ast::TyKind::UnsafeBinder(f) => {
self.ibox(INDENT_UNIT);
self.word("unsafe");
self.print_generic_params(&f.generic_params);
self.nbsp();
self.print_type(&f.inner_ty);
self.end();
}
ast::TyKind::Path(None, path) => {
self.print_path(path, false, 0);
}
Expand Down
19 changes: 19 additions & 0 deletions compiler/rustc_ast_pretty/src/pprust/state/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,25 @@ impl<'a> State<'a> {
self.word_nbsp("try");
self.print_block_with_attrs(blk, attrs)
}
ast::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
self.word("builtin # ");
match kind {
ast::UnsafeBinderCastKind::Wrap => self.word("wrap_unsafe_binder"),
ast::UnsafeBinderCastKind::Unwrap => self.word("unwrap_unsafe_binder"),
}
self.popen();
self.ibox(0);
self.print_expr(expr, FixupContext::default());

if let Some(ty) = ty {
self.word(",");
self.space();
self.print_type(ty);
}

self.end();
self.pclose();
}
ast::ExprKind::Err(_) => {
self.popen();
self.word("/*ERROR*/");
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3950,7 +3950,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Subtype(_)
| ProjectionElem::Index(_) => kind,
| ProjectionElem::Index(_)
| ProjectionElem::UnsafeBinderCast(..) => kind,
},
place_ty.projection_ty(tcx, elem),
)
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_borrowck/src/diagnostics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
ProjectionElem::Downcast(..) => (),
ProjectionElem::OpaqueCast(..) => (),
ProjectionElem::Subtype(..) => (),
ProjectionElem::UnsafeBinderCast(..) => (),
ProjectionElem::Field(field, _ty) => {
// FIXME(project-rfc_2229#36): print capture precisely here.
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
Expand Down Expand Up @@ -323,9 +324,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
}
ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
ProjectionElem::Subtype(ty) | ProjectionElem::OpaqueCast(ty) => {
PlaceTy::from_ty(*ty)
}
ProjectionElem::Subtype(ty)
| ProjectionElem::OpaqueCast(ty)
| ProjectionElem::UnsafeBinderCast(_, ty) => PlaceTy::from_ty(*ty),
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
},
};
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(..),
| ProjectionElem::Downcast(..)
| ProjectionElem::UnsafeBinderCast(..),
],
} => bug!("Unexpected immutable place."),
}
Expand Down
12 changes: 10 additions & 2 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1634,6 +1634,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
| ty::Slice(_)
| ty::FnDef(_, _)
| ty::FnPtr(..)
| ty::UnsafeBinder(_)
| ty::Dynamic(_, _, _)
| ty::Closure(_, _)
| ty::CoroutineClosure(_, _)
Expand Down Expand Up @@ -1679,6 +1680,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
| ty::Ref(_, _, _)
| ty::FnDef(_, _)
| ty::FnPtr(..)
| ty::UnsafeBinder(_)
| ty::Dynamic(_, _, _)
| ty::CoroutineWitness(..)
| ty::Never
Expand Down Expand Up @@ -1722,7 +1724,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
// So it's safe to skip these.
ProjectionElem::OpaqueCast(_)
| ProjectionElem::Subtype(_)
| ProjectionElem::Downcast(_, _) => (),
| ProjectionElem::Downcast(_, _)
| ProjectionElem::UnsafeBinderCast(_, _) => (),
}

place_ty = place_ty.projection_ty(tcx, elem);
Expand Down Expand Up @@ -1956,6 +1959,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
// FIXME: is this true even if P is an adt with a dtor?
{ }

ProjectionElem::UnsafeBinderCast(..) => {
check_parent_of_field(self, location, place_base, span, state);
}

// assigning to (*P) requires P to be initialized
ProjectionElem::Deref => {
self.check_if_full_path_is_moved(
Expand Down Expand Up @@ -2339,7 +2346,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
| ProjectionElem::Subslice { .. }
| ProjectionElem::Subtype(..)
| ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Downcast(..) => {
| ProjectionElem::Downcast(..)
| ProjectionElem::UnsafeBinderCast(..) => {
let upvar_field_projection = self.is_upvar_field_projection(place);
if let Some(field) = upvar_field_projection {
let upvar = &self.upvars[field.index()];
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_borrowck/src/places_conflict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,8 @@ fn place_components_conflict<'tcx>(
| (ProjectionElem::Subslice { .. }, _, _)
| (ProjectionElem::OpaqueCast { .. }, _, _)
| (ProjectionElem::Subtype(_), _, _)
| (ProjectionElem::Downcast { .. }, _, _) => {
| (ProjectionElem::Downcast { .. }, _, _)
| (ProjectionElem::UnsafeBinderCast(..), _, _) => {
// Recursive case. This can still be disjoint on a
// further iteration if this a shallow access and
// there's a deref later on, e.g., a borrow
Expand Down Expand Up @@ -519,5 +520,9 @@ fn place_projection_conflict<'tcx>(
pi1_elem,
pi2_elem
),

(ProjectionElem::UnsafeBinderCast(..), _) => {
todo!()
}
}
}
4 changes: 4 additions & 0 deletions compiler/rustc_borrowck/src/prefixes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ impl<'tcx> Iterator for Prefixes<'tcx> {
self.next = Some(cursor_base);
return Some(cursor);
}
ProjectionElem::UnsafeBinderCast(..) => {
self.next = Some(cursor_base);
return Some(cursor);
}
ProjectionElem::Downcast(..)
| ProjectionElem::Subslice { .. }
| ProjectionElem::OpaqueCast { .. }
Expand Down
Loading
Loading