Skip to content

Commit c01d5e0

Browse files
committed
Auto merge of rust-lang#17984 - ShoyuVanilla:cast, r=Veykril
feat: Implement cast typecheck and diagnostics Fixes rust-lang#17897 and fixes rust-lang#16564 Mainly adopted from https://github.com/rust-lang/rust/blob/100fde5246bf56f22fb5cc85374dd841296fce0e/compiler/rustc_hir_typeck/src/cast.rs
2 parents 6faf409 + 111c690 commit c01d5e0

File tree

25 files changed

+1614
-93
lines changed

25 files changed

+1614
-93
lines changed

src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs

+22
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use triomphe::Arc;
1414
use crate::{
1515
builtin_type::{BuiltinInt, BuiltinUint},
1616
db::DefDatabase,
17+
hir::Expr,
1718
item_tree::{
1819
AttrOwner, Field, FieldParent, FieldsShape, ItemTree, ModItem, RawVisibilityId, TreeId,
1920
},
@@ -317,6 +318,27 @@ impl EnumData {
317318
_ => IntegerType::Pointer(true),
318319
}
319320
}
321+
322+
// [Adopted from rustc](https://github.com/rust-lang/rust/blob/bd53aa3bf7a24a70d763182303bd75e5fc51a9af/compiler/rustc_middle/src/ty/adt.rs#L446-L448)
323+
pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool {
324+
self.variants.iter().all(|(v, _)| {
325+
// The condition check order is slightly modified from rustc
326+
// to improve performance by early returning with relatively fast checks
327+
let variant = &db.enum_variant_data(*v).variant_data;
328+
if !variant.fields().is_empty() {
329+
return false;
330+
}
331+
// The outer if condition is whether this variant has const ctor or not
332+
if !matches!(variant.kind(), StructKind::Unit) {
333+
let body = db.body((*v).into());
334+
// A variant with explicit discriminant
335+
if body.exprs[body.body_expr] != Expr::Missing {
336+
return false;
337+
}
338+
}
339+
true
340+
})
341+
}
320342
}
321343

322344
impl EnumVariantData {

src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,13 @@ fn floating_point() {
186186

187187
#[test]
188188
fn casts() {
189-
check_number(r#"const GOAL: usize = 12 as *const i32 as usize"#, 12);
189+
check_number(
190+
r#"
191+
//- minicore: sized
192+
const GOAL: usize = 12 as *const i32 as usize
193+
"#,
194+
12,
195+
);
190196
check_number(
191197
r#"
192198
//- minicore: coerce_unsized, index, slice
@@ -204,7 +210,7 @@ fn casts() {
204210
r#"
205211
//- minicore: coerce_unsized, index, slice
206212
const GOAL: i16 = {
207-
let a = &mut 5;
213+
let a = &mut 5_i16;
208214
let z = a as *mut _;
209215
unsafe { *z }
210216
};
@@ -244,7 +250,13 @@ fn casts() {
244250
"#,
245251
4,
246252
);
247-
check_number(r#"const GOAL: i32 = -12i8 as i32"#, -12);
253+
check_number(
254+
r#"
255+
//- minicore: sized
256+
const GOAL: i32 = -12i8 as i32
257+
"#,
258+
-12,
259+
);
248260
}
249261

250262
#[test]
@@ -1911,6 +1923,7 @@ fn function_pointer() {
19111923
);
19121924
check_number(
19131925
r#"
1926+
//- minicore: sized
19141927
fn add2(x: u8) -> u8 {
19151928
x + 2
19161929
}
@@ -2422,6 +2435,7 @@ fn statics() {
24222435
fn extern_weak_statics() {
24232436
check_number(
24242437
r#"
2438+
//- minicore: sized
24252439
extern "C" {
24262440
#[linkage = "extern_weak"]
24272441
static __dso_handle: *mut u8;
@@ -2716,6 +2730,7 @@ fn const_trait_assoc() {
27162730
);
27172731
check_number(
27182732
r#"
2733+
//- minicore: sized
27192734
struct S<T>(*mut T);
27202735
27212736
trait MySized: Sized {

src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs

+1
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ fn saturating() {
311311
fn allocator() {
312312
check_number(
313313
r#"
314+
//- minicore: sized
314315
extern "Rust" {
315316
#[rustc_allocator]
316317
fn __rust_alloc(size: usize, align: usize) -> *mut u8;

src/tools/rust-analyzer/crates/hir-ty/src/infer.rs

+27-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
//! to certain types. To record this, we use the union-find implementation from
1414
//! the `ena` crate, which is extracted from rustc.
1515
16-
mod cast;
16+
pub(crate) mod cast;
1717
pub(crate) mod closure;
1818
mod coerce;
1919
mod expr;
@@ -76,7 +76,7 @@ pub use coerce::could_coerce;
7676
#[allow(unreachable_pub)]
7777
pub use unify::{could_unify, could_unify_deeply};
7878

79-
use cast::CastCheck;
79+
use cast::{CastCheck, CastError};
8080
pub(crate) use closure::{CaptureKind, CapturedItem, CapturedItemWithoutTy};
8181

8282
/// The entry point of type inference.
@@ -254,6 +254,16 @@ pub enum InferenceDiagnostic {
254254
expr: ExprId,
255255
expected: Ty,
256256
},
257+
CastToUnsized {
258+
expr: ExprId,
259+
cast_ty: Ty,
260+
},
261+
InvalidCast {
262+
expr: ExprId,
263+
error: CastError,
264+
expr_ty: Ty,
265+
cast_ty: Ty,
266+
},
257267
}
258268

259269
/// A mismatch between an expected and an inferred type.
@@ -456,6 +466,7 @@ pub struct InferenceResult {
456466
pub(crate) closure_info: FxHashMap<ClosureId, (Vec<CapturedItem>, FnTrait)>,
457467
// FIXME: remove this field
458468
pub mutated_bindings_in_closure: FxHashSet<BindingId>,
469+
pub coercion_casts: FxHashSet<ExprId>,
459470
}
460471

461472
impl InferenceResult {
@@ -666,7 +677,7 @@ impl<'a> InferenceContext<'a> {
666677
let InferenceContext {
667678
mut table,
668679
mut result,
669-
deferred_cast_checks,
680+
mut deferred_cast_checks,
670681
tuple_field_accesses_rev,
671682
..
672683
} = self;
@@ -695,15 +706,26 @@ impl<'a> InferenceContext<'a> {
695706
closure_info: _,
696707
mutated_bindings_in_closure: _,
697708
tuple_field_access_types: _,
709+
coercion_casts,
698710
} = &mut result;
699711

700712
table.fallback_if_possible();
701713

702714
// Comment from rustc:
703715
// Even though coercion casts provide type hints, we check casts after fallback for
704716
// backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
705-
for cast in deferred_cast_checks {
706-
cast.check(&mut table);
717+
let mut apply_adjustments = |expr, adj| {
718+
expr_adjustments.insert(expr, adj);
719+
};
720+
let mut set_coercion_cast = |expr| {
721+
coercion_casts.insert(expr);
722+
};
723+
for cast in deferred_cast_checks.iter_mut() {
724+
if let Err(diag) =
725+
cast.check(&mut table, &mut apply_adjustments, &mut set_coercion_cast)
726+
{
727+
diagnostics.push(diag);
728+
}
707729
}
708730

709731
// FIXME resolve obligations as well (use Guidance if necessary)

0 commit comments

Comments
 (0)