Skip to content

Commit 76386bd

Browse files
Make dyn* cast into a coercion
1 parent edabf59 commit 76386bd

File tree

13 files changed

+73
-68
lines changed

13 files changed

+73
-68
lines changed

Diff for: compiler/rustc_hir_analysis/src/check/cast.rs

+5-58
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,12 @@ use crate::type_error_struct;
3535
use hir::def_id::LOCAL_CRATE;
3636
use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed};
3737
use rustc_hir as hir;
38-
use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode};
3938
use rustc_middle::mir::Mutability;
4039
use rustc_middle::ty::adjustment::AllowTwoPhase;
4140
use rustc_middle::ty::cast::{CastKind, CastTy};
4241
use rustc_middle::ty::error::TypeError;
4342
use rustc_middle::ty::subst::SubstsRef;
44-
use rustc_middle::ty::{self, Binder, Ty, TypeAndMut, TypeVisitable, VariantDef};
43+
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
4544
use rustc_session::lint;
4645
use rustc_session::Session;
4746
use rustc_span::symbol::sym;
@@ -218,58 +217,10 @@ pub fn check_cast<'tcx>(
218217
cast_span: Span,
219218
span: Span,
220219
) -> CastCheckResult<'tcx> {
221-
if cast_ty.is_dyn_star() {
222-
check_dyn_star_cast(fcx, expr, expr_ty, cast_ty)
223-
} else {
224-
match CastCheck::new(fcx, expr, expr_ty, cast_ty, cast_span, span) {
225-
Ok(check) => CastCheckResult::Deferred(check),
226-
Err(e) => CastCheckResult::Err(e),
227-
}
228-
}
229-
}
230-
231-
fn check_dyn_star_cast<'tcx>(
232-
fcx: &FnCtxt<'_, 'tcx>,
233-
expr: &'tcx hir::Expr<'tcx>,
234-
expr_ty: Ty<'tcx>,
235-
cast_ty: Ty<'tcx>,
236-
) -> CastCheckResult<'tcx> {
237-
// Find the bounds in the dyn*. For eaxmple, if we have
238-
//
239-
// let x = 22_usize as dyn* (Clone + Debug + 'static)
240-
//
241-
// this would return `existential_predicates = [?Self: Clone, ?Self: Debug]` and `region = 'static`.
242-
let (existential_predicates, region) = match cast_ty.kind() {
243-
ty::Dynamic(predicates, region, ty::DynStar) => (predicates, region),
244-
_ => panic!("Invalid dyn* cast_ty"),
245-
};
246-
247-
let cause = ObligationCause::new(
248-
expr.span,
249-
fcx.body_id,
250-
// FIXME(dyn-star): Use a better obligation cause code
251-
ObligationCauseCode::MiscObligation,
252-
);
253-
254-
// For each existential predicate (e.g., `?Self: Clone`) substitute
255-
// the type of the expression (e.g., `usize` in our example above)
256-
// and then require that the resulting predicate (e.g., `usize: Clone`)
257-
// holds (it does).
258-
for existential_predicate in existential_predicates.iter() {
259-
let predicate = existential_predicate.with_self_ty(fcx.tcx, expr_ty);
260-
fcx.register_predicate(Obligation::new(cause.clone(), fcx.param_env, predicate));
220+
match CastCheck::new(fcx, expr, expr_ty, cast_ty, cast_span, span) {
221+
Ok(check) => CastCheckResult::Deferred(check),
222+
Err(e) => CastCheckResult::Err(e),
261223
}
262-
263-
// Enforce the region bound `'static` (e.g., `usize: 'static`, in our example).
264-
fcx.register_predicate(Obligation::new(
265-
cause,
266-
fcx.param_env,
267-
fcx.tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives(
268-
ty::OutlivesPredicate(expr_ty, *region),
269-
))),
270-
));
271-
272-
CastCheckResult::Ok
273224
}
274225

275226
impl<'a, 'tcx> CastCheck<'tcx> {
@@ -934,11 +885,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
934885

935886
(Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast),
936887

937-
// FIXME(dyn-star): this needs more conditions...
938-
(_, DynStar) => Ok(CastKind::DynStarCast),
939-
940-
// FIXME(dyn-star): do we want to allow dyn* upcasting or other casts?
941-
(DynStar, _) => Err(CastError::IllegalCast),
888+
(_, DynStar) | (DynStar, _) => bug!("should be handled by `try_coerce`"),
942889
}
943890
}
944891

Diff for: compiler/rustc_hir_analysis/src/check/coercion.rs

+50
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
216216
ty::Ref(r_b, _, mutbl_b) => {
217217
return self.coerce_borrowed_pointer(a, b, r_b, mutbl_b);
218218
}
219+
ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star => {
220+
return self.coerce_dyn_star(a, b, predicates, region);
221+
}
219222
_ => {}
220223
}
221224

@@ -745,6 +748,53 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
745748
Ok(coercion)
746749
}
747750

751+
fn coerce_dyn_star(
752+
&self,
753+
a: Ty<'tcx>,
754+
b: Ty<'tcx>,
755+
predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
756+
b_region: ty::Region<'tcx>,
757+
) -> CoerceResult<'tcx> {
758+
if !self.tcx.features().dyn_star {
759+
return Err(TypeError::Mismatch);
760+
}
761+
762+
if let ty::Dynamic(a_data, _, _) = a.kind()
763+
&& let ty::Dynamic(b_data, _, _) = b.kind()
764+
{
765+
if a_data.principal_def_id() == b_data.principal_def_id() {
766+
return self.unify_and(a, b, |_| vec![]);
767+
} else {
768+
bug!("dyn* trait upcasting is not supported");
769+
}
770+
}
771+
772+
let obligations = predicates
773+
.iter()
774+
.map(|predicate| {
775+
// For each existential predicate (e.g., `?Self: Clone`) substitute
776+
// the type of the expression (e.g., `usize` in our example above)
777+
// and then require that the resulting predicate (e.g., `usize: Clone`)
778+
// holds (it does).
779+
let predicate = predicate.with_self_ty(self.tcx, a);
780+
Obligation::new(self.cause.clone(), self.param_env, predicate)
781+
})
782+
// Enforce the region bound `'static` (e.g., `usize: 'static`, in our example).
783+
.chain([Obligation::new(
784+
self.cause.clone(),
785+
self.param_env,
786+
self.tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
787+
ty::OutlivesPredicate(a, b_region),
788+
))),
789+
)])
790+
.collect();
791+
792+
Ok(InferOk {
793+
value: (vec![Adjustment { kind: Adjust::DynStar, target: b }], b),
794+
obligations,
795+
})
796+
}
797+
748798
fn coerce_from_safe_fn<F, G>(
749799
&self,
750800
a: Ty<'tcx>,

Diff for: compiler/rustc_hir_analysis/src/expr_use_visitor.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
583583
for adjustment in adjustments {
584584
debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
585585
match adjustment.kind {
586-
adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => {
586+
adjustment::Adjust::NeverToAny
587+
| adjustment::Adjust::Pointer(_)
588+
| adjustment::Adjust::DynStar => {
587589
// Creating a closure/fn-pointer or unsizing consumes
588590
// the input and stores it into the resulting rvalue.
589591
self.delegate_consume(&place_with_id, place_with_id.hir_id);

Diff for: compiler/rustc_hir_analysis/src/mem_categorization.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
292292

293293
adjustment::Adjust::NeverToAny
294294
| adjustment::Adjust::Pointer(_)
295-
| adjustment::Adjust::Borrow(_) => {
295+
| adjustment::Adjust::Borrow(_)
296+
| adjustment::Adjust::DynStar => {
296297
// Result is an rvalue.
297298
Ok(self.cat_rvalue(expr.hir_id, expr.span, target))
298299
}

Diff for: compiler/rustc_middle/src/mir/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1824,7 +1824,6 @@ impl<'tcx> Rvalue<'tcx> {
18241824
// While the model is undecided, we should be conservative. See
18251825
// <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
18261826
Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false,
1827-
Rvalue::Cast(CastKind::DynStar, _, _) => false,
18281827

18291828
Rvalue::Use(_)
18301829
| Rvalue::CopyForDeref(_)
@@ -1841,7 +1840,8 @@ impl<'tcx> Rvalue<'tcx> {
18411840
| CastKind::FnPtrToPtr
18421841
| CastKind::PtrToPtr
18431842
| CastKind::Pointer(_)
1844-
| CastKind::PointerFromExposedAddress,
1843+
| CastKind::PointerFromExposedAddress
1844+
| CastKind::DynStar,
18451845
_,
18461846
_,
18471847
)

Diff for: compiler/rustc_middle/src/ty/adjustment.rs

+3
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ pub enum Adjust<'tcx> {
101101
Borrow(AutoBorrow<'tcx>),
102102

103103
Pointer(PointerCast),
104+
105+
/// Cast into a dyn* object.
106+
DynStar,
104107
}
105108

106109
/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`

Diff for: compiler/rustc_mir_build/src/thir/cx/expr.rs

+1
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ impl<'tcx> Cx<'tcx> {
159159
Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => {
160160
ExprKind::AddressOf { mutability, arg: self.thir.exprs.push(expr) }
161161
}
162+
Adjust::DynStar => ExprKind::Cast { source: self.thir.exprs.push(expr) },
162163
};
163164

164165
Expr { temp_lifetime, ty: adjustment.target, span, kind }

Diff for: src/test/ui/dyn-star/const.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::fmt::Debug;
66

77
fn make_dyn_star() {
88
let i = 42usize;
9-
let dyn_i: dyn* Debug = i as dyn* Debug;
9+
let dyn_i: dyn* Debug = i;
1010
}
1111

1212
fn main() {

Diff for: src/test/ui/dyn-star/drop.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ impl Drop for Foo {
1515
}
1616

1717
fn make_dyn_star(i: Foo) {
18-
let _dyn_i: dyn* Debug = i as dyn* Debug;
18+
let _dyn_i: dyn* Debug = i;
1919
}
2020

2121
fn main() {

Diff for: src/test/ui/dyn-star/error.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ trait Foo {}
77

88
fn make_dyn_star() {
99
let i = 42;
10-
let dyn_i: dyn* Foo = i as dyn* Foo; //~ ERROR trait bound `{integer}: Foo` is not satisfied
10+
let dyn_i: dyn* Foo = i; //~ ERROR trait bound `{integer}: Foo` is not satisfied
1111
}
1212

1313
fn main() {}

Diff for: src/test/ui/dyn-star/error.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
error[E0277]: the trait bound `{integer}: Foo` is not satisfied
22
--> $DIR/error.rs:10:27
33
|
4-
LL | let dyn_i: dyn* Foo = i as dyn* Foo;
4+
LL | let dyn_i: dyn* Foo = i;
55
| ^ the trait `Foo` is not implemented for `{integer}`
66

77
error: aborting due to previous error

Diff for: src/test/ui/dyn-star/make-dyn-star.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use std::fmt::Debug;
66

77
fn make_dyn_star(i: usize) {
8-
let _dyn_i: dyn* Debug = i as dyn* Debug;
8+
let _dyn_i: dyn* Debug = i;
99
}
1010

1111
fn main() {

Diff for: src/test/ui/dyn-star/method.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// run-pass
2+
23
#![feature(dyn_star)]
34
#![allow(incomplete_features)]
45

@@ -17,7 +18,7 @@ fn invoke_dyn_star(i: dyn* Foo) -> usize {
1718
}
1819

1920
fn make_and_invoke_dyn_star(i: usize) -> usize {
20-
let dyn_i: dyn* Foo = i as dyn* Foo;
21+
let dyn_i: dyn* Foo = i;
2122
invoke_dyn_star(dyn_i)
2223
}
2324

0 commit comments

Comments
 (0)