Skip to content

Commit

Permalink
Begin to implement type system layer of unsafe binders
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Dec 21, 2024
1 parent 54dcff1 commit 211eab4
Show file tree
Hide file tree
Showing 77 changed files with 512 additions and 109 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
&self,
negative_impls,
span.to(of_trait.as_ref().map_or(span, |t| t.path.span)),
"negative trait bounds are not yet fully implemented; \
"negative trait bounds are not fully implemented; \
use marker types for now"
);
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1602,6 +1602,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
| ty::CoroutineWitness(..)
| ty::Never
| ty::Tuple(_)
| ty::UnsafeBinder(_)
| ty::Alias(_, _)
| ty::Param(_)
| ty::Bound(_, _)
Expand Down Expand Up @@ -1643,6 +1644,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
| ty::Dynamic(_, _, _)
| ty::CoroutineWitness(..)
| ty::Never
| ty::UnsafeBinder(_)
| ty::Alias(_, _)
| ty::Param(_)
| ty::Bound(_, _)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ fn push_debuginfo_type_name<'tcx>(
push_closure_or_coroutine_name(tcx, def_id, args, qualified, output, visited);
}
}
ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binders)"),
ty::Param(_)
| ty::Error(_)
| ty::Infer(_)
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_const_eval/src/const_eval/valtrees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,8 @@ fn const_to_valtree_inner<'tcx>(
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType(ty)),
| ty::CoroutineWitness(..)
| ty::UnsafeBinder(_) => Err(ValTreeCreationError::NonSupportedType(ty)),
}
}

Expand Down Expand Up @@ -358,7 +359,10 @@ pub fn valtree_to_const_value<'tcx>(
| ty::FnPtr(..)
| ty::Str
| ty::Slice(_)
| ty::Dynamic(..) => bug!("no ValTree should have been created for type {:?}", ty.kind()),
| ty::Dynamic(..)
| ty::UnsafeBinder(_) => {
bug!("no ValTree should have been created for type {:?}", ty.kind())
}
}
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)
| ty::CoroutineWitness(..)
| ty::UnsafeBinder(_)
| ty::Never
| ty::Tuple(_)
| ty::Error(_) => ConstValue::from_target_usize(0u64, &tcx),
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_const_eval/src/interpret/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// We don't want to do any queries, so there is not much we can do with ADTs.
ty::Adt(..) => false,

ty::UnsafeBinder(ty) => is_very_trivially_sized(ty.skip_binder()),

ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => false,

ty::Infer(ty::TyVar(_)) => false,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
// Nothing to check.
interp_ok(true)
}
ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"),
// The above should be all the primitive types. The rest is compound, we
// check them by visiting their fields/variants.
ty::Adt(..)
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_const_eval/src/util/type_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
| ty::FnPtr(..)
| ty::Never
| ty::Tuple(_)
| ty::Dynamic(_, _, _) => self.pretty_print_type(ty),
| ty::Dynamic(_, _, _)
| ty::UnsafeBinder(_) => self.pretty_print_type(ty),

// Placeholders (all printed as `_` to uniformize them).
ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => {
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,8 @@ impl<'tcx> InherentCollect<'tcx> {
| ty::Ref(..)
| ty::Never
| ty::FnPtr(..)
| ty::Tuple(..) => self.check_primitive_impl(id, self_ty),
| ty::Tuple(..)
| ty::UnsafeBinder(_) => self.check_primitive_impl(id, self_ty),
ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _) | ty::Param(_) => {
Err(self.tcx.dcx().emit_err(errors::InherentNominal { span: item_span }))
}
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_hir_analysis/src/coherence/orphan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,8 @@ pub(crate) fn orphan_check_impl(
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::Never
| ty::Tuple(..) => (LocalImpl::Allow, NonlocalImpl::DisallowOther),
| ty::Tuple(..)
| ty::UnsafeBinder(_) => (LocalImpl::Allow, NonlocalImpl::DisallowOther),

ty::Closure(..)
| ty::CoroutineClosure(..)
Expand Down
14 changes: 7 additions & 7 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2318,13 +2318,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self.lower_fn_ty(hir_ty.hir_id, bf.safety, bf.abi, bf.decl, None, Some(hir_ty)),
)
}
hir::TyKind::UnsafeBinder(_binder) => {
let guar = self
.dcx()
.struct_span_err(hir_ty.span, "unsafe binders are not yet implemented")
.emit();
Ty::new_error(tcx, guar)
}
hir::TyKind::UnsafeBinder(binder) => Ty::new_unsafe_binder(
tcx,
ty::Binder::bind_with_vars(
self.lower_ty(binder.inner_ty),
tcx.late_bound_vars(hir_ty.hir_id),
),
),
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
if let Some(guar) = self.prohibit_or_lint_bare_trait_object_ty(hir_ty) {
// Don't continue with type analysis if the `dyn` keyword is missing
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_hir_analysis/src/variance/constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
self.add_constraints_from_sig(current, sig_tys.with(hdr), variance);
}

ty::UnsafeBinder(ty) => {
// FIXME(unsafe_binders): This is covariant, right?
self.add_constraints_from_ty(current, ty.skip_binder(), variance);
}

ty::Error(_) => {
// we encounter this when walking the trait references for object
// types, where we use Error as the Self type
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_hir_typeck/src/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Some(&f) => self.pointer_kind(f, span)?,
},

ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"),

// Pointers to foreign types are thin, despite being unsized
ty::Foreign(..) => Some(PointerKind::Thin),
// We should really try to normalize here.
Expand Down
98 changes: 89 additions & 9 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -574,8 +574,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.check_expr_index(base, idx, expr, brackets_span)
}
ExprKind::Yield(value, _) => self.check_expr_yield(value, expr),
ExprKind::UnsafeBinderCast(kind, expr, ty) => {
self.check_expr_unsafe_binder_cast(kind, expr, ty, expected)
ExprKind::UnsafeBinderCast(kind, inner_expr, ty) => {
self.check_expr_unsafe_binder_cast(expr.span, kind, inner_expr, ty, expected)
}
ExprKind::Err(guar) => Ty::new_error(tcx, guar),
}
Expand Down Expand Up @@ -1649,14 +1649,94 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

fn check_expr_unsafe_binder_cast(
&self,
_kind: hir::UnsafeBinderCastKind,
expr: &'tcx hir::Expr<'tcx>,
_hir_ty: Option<&'tcx hir::Ty<'tcx>>,
_expected: Expectation<'tcx>,
span: Span,
kind: hir::UnsafeBinderCastKind,
inner_expr: &'tcx hir::Expr<'tcx>,
hir_ty: Option<&'tcx hir::Ty<'tcx>>,
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
let guar =
self.dcx().struct_span_err(expr.span, "unsafe binders are not yet implemented").emit();
Ty::new_error(self.tcx, guar)
self.dcx().span_err(inner_expr.span, "unsafe binder casts are not fully implemented");

match kind {
hir::UnsafeBinderCastKind::Wrap => {
let ascribed_ty =
hir_ty.map(|hir_ty| self.lower_ty_saving_user_provided_ty(hir_ty));
let expected_ty = expected.only_has_type(self);
let binder_ty = match (ascribed_ty, expected_ty) {
(Some(ascribed_ty), Some(expected_ty)) => {
self.demand_eqtype(inner_expr.span, expected_ty, ascribed_ty);
expected_ty
}
(Some(ty), None) | (None, Some(ty)) => ty,
// This will always cause a structural resolve error, but we do it
// so we don't need to manually report an E0282 both on this codepath
// and in the others; it all happens in `structurally_resolve_type`.
(None, None) => self.next_ty_var(inner_expr.span),
};

let binder_ty = self.structurally_resolve_type(inner_expr.span, binder_ty);
let hint_ty = match *binder_ty.kind() {
ty::UnsafeBinder(binder) => self.instantiate_binder_with_fresh_vars(
inner_expr.span,
infer::BoundRegionConversionTime::HigherRankedType,
binder.into(),
),
ty::Error(e) => Ty::new_error(self.tcx, e),
_ => {
let guar = self
.dcx()
.struct_span_err(
hir_ty.map_or(span, |hir_ty| hir_ty.span),
format!(
"`wrap_binder!()` can only wrap into unsafe binder, not {}",
binder_ty.sort_string(self.tcx)
),
)
.with_note("unsafe binders are the only valid output of wrap")
.emit();
Ty::new_error(self.tcx, guar)
}
};

self.check_expr_has_type_or_error(inner_expr, hint_ty, |_| {});

binder_ty
}
hir::UnsafeBinderCastKind::Unwrap => {
let ascribed_ty =
hir_ty.map(|hir_ty| self.lower_ty_saving_user_provided_ty(hir_ty));
let hint_ty = ascribed_ty.unwrap_or_else(|| self.next_ty_var(inner_expr.span));
// FIXME(unsafe_binders): coerce here if needed?
let binder_ty = self.check_expr_has_type_or_error(inner_expr, hint_ty, |_| {});

// Unwrap the binder. This will be ambiguous if it's an infer var, and will error
// if it's not an unsafe binder.
let binder_ty = self.structurally_resolve_type(inner_expr.span, binder_ty);
match *binder_ty.kind() {
ty::UnsafeBinder(binder) => self.instantiate_binder_with_fresh_vars(
inner_expr.span,
infer::BoundRegionConversionTime::HigherRankedType,
binder.into(),
),
ty::Error(e) => Ty::new_error(self.tcx, e),
_ => {
let guar = self
.dcx()
.struct_span_err(
hir_ty.map_or(inner_expr.span, |hir_ty| hir_ty.span),
format!(
"expected unsafe binder, found {} as input of \
`unwrap_binder!()`",
binder_ty.sort_string(self.tcx)
),
)
.with_note("only an unsafe binder type can be unwrapped")
.emit();
Ty::new_error(self.tcx, guar)
}
}
}
}
}

fn check_expr_array(
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::Dynamic(..)
| ty::UnsafeBinder(_)
| ty::Never
| ty::Tuple(..)
| ty::Alias(..)
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_lint/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1284,6 +1284,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
FfiSafe
}

ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"),

ty::Param(..)
| ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..)
| ty::Infer(..)
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
| ty::CoroutineClosure(..)
| ty::Coroutine(_, _)
| ty::Never
| ty::Tuple(_) => {
| ty::Tuple(_)
| ty::UnsafeBinder(_) => {
let simp = ty::fast_reject::simplify_type(
tcx,
self_ty,
Expand Down Expand Up @@ -2295,6 +2296,7 @@ impl<'tcx> TyCtxt<'tcx> {
Ref,
FnDef,
FnPtr,
UnsafeBinder,
Placeholder,
Coroutine,
CoroutineWitness,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ impl<'tcx> Ty<'tcx> {
_ => "fn item".into(),
},
ty::FnPtr(..) => "fn pointer".into(),
ty::UnsafeBinder(_) => "unsafe binder".into(),
ty::Dynamic(..) => "trait object".into(),
ty::Closure(..) | ty::CoroutineClosure(..) => "closure".into(),
ty::Coroutine(def_id, ..) => {
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_middle/src/ty/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,12 @@ impl FlagComputation {
&ty::FnPtr(sig_tys, _) => self.bound_computation(sig_tys, |computation, sig_tys| {
computation.add_tys(sig_tys.inputs_and_output);
}),

&ty::UnsafeBinder(bound_ty) => {
self.bound_computation(bound_ty.into(), |computation, ty| {
computation.add_ty(ty);
})
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,11 @@ where
bug!("TyAndLayout::field({:?}): not applicable", this)
}

ty::UnsafeBinder(bound_ty) => {
let ty = tcx.instantiate_bound_regions_with_erased(bound_ty.into());
field_ty_or_layout(TyAndLayout { ty, ..this }, cx, i)
}

// Potentially-wide pointers.
ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
assert!(i < this.fields.count());
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/print/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ fn characteristic_def_id_of_type_cached<'a>(
| ty::Uint(_)
| ty::Str
| ty::FnPtr(..)
| ty::UnsafeBinder(_)
| ty::Alias(..)
| ty::Placeholder(..)
| ty::Param(_)
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
}
}
ty::FnPtr(ref sig_tys, hdr) => p!(print(sig_tys.with(hdr))),
ty::UnsafeBinder(ref bound_ty) => {
// FIXME(unsafe_binders): Make this print `unsafe<>` rather than `for<>`.
self.wrap_binder(bound_ty, |ty, cx| cx.pretty_print_type(*ty))?;
}
ty::Infer(infer_ty) => {
if self.should_print_verbose() {
p!(write("{:?}", ty.kind()));
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/ty/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
ty::Tuple(ts) => ty::Tuple(ts.try_fold_with(folder)?),
ty::FnDef(def_id, args) => ty::FnDef(def_id, args.try_fold_with(folder)?),
ty::FnPtr(sig_tys, hdr) => ty::FnPtr(sig_tys.try_fold_with(folder)?, hdr),
ty::UnsafeBinder(f) => ty::UnsafeBinder(f.try_fold_with(folder)?),
ty::Ref(r, ty, mutbl) => {
ty::Ref(r.try_fold_with(folder)?, ty.try_fold_with(folder)?, mutbl)
}
Expand Down Expand Up @@ -443,6 +444,7 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for Ty<'tcx> {
ty::Tuple(ts) => ts.visit_with(visitor),
ty::FnDef(_, args) => args.visit_with(visitor),
ty::FnPtr(ref sig_tys, _) => sig_tys.visit_with(visitor),
ty::UnsafeBinder(ref f) => f.visit_with(visitor),
ty::Ref(r, ty, _) => {
try_visit!(r.visit_with(visitor));
ty.visit_with(visitor)
Expand Down
Loading

0 comments on commit 211eab4

Please sign in to comment.