Skip to content

Commit c113030

Browse files
committed
Auto merge of #76906 - Nicholas-Baron:shorten_typeck_check, r=oli-obk
Split rustc_typeck::check into separate files Contributing to #60302.
2 parents 44ae0b8 + ccd218d commit c113030

File tree

7 files changed

+5124
-5006
lines changed

7 files changed

+5124
-5006
lines changed

compiler/rustc_typeck/src/check/check.rs

+1,344
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use rustc_span::source_map::DUMMY_SP;
2+
use rustc_span::{self, Span};
3+
use std::{cmp, ops};
4+
5+
/// Tracks whether executing a node may exit normally (versus
6+
/// return/break/panic, which "diverge", leaving dead code in their
7+
/// wake). Tracked semi-automatically (through type variables marked
8+
/// as diverging), with some manual adjustments for control-flow
9+
/// primitives (approximating a CFG).
10+
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
11+
pub enum Diverges {
12+
/// Potentially unknown, some cases converge,
13+
/// others require a CFG to determine them.
14+
Maybe,
15+
16+
/// Definitely known to diverge and therefore
17+
/// not reach the next sibling or its parent.
18+
Always {
19+
/// The `Span` points to the expression
20+
/// that caused us to diverge
21+
/// (e.g. `return`, `break`, etc).
22+
span: Span,
23+
/// In some cases (e.g. a `match` expression
24+
/// where all arms diverge), we may be
25+
/// able to provide a more informative
26+
/// message to the user.
27+
/// If this is `None`, a default message
28+
/// will be generated, which is suitable
29+
/// for most cases.
30+
custom_note: Option<&'static str>,
31+
},
32+
33+
/// Same as `Always` but with a reachability
34+
/// warning already emitted.
35+
WarnedAlways,
36+
}
37+
38+
// Convenience impls for combining `Diverges`.
39+
40+
impl ops::BitAnd for Diverges {
41+
type Output = Self;
42+
fn bitand(self, other: Self) -> Self {
43+
cmp::min(self, other)
44+
}
45+
}
46+
47+
impl ops::BitOr for Diverges {
48+
type Output = Self;
49+
fn bitor(self, other: Self) -> Self {
50+
cmp::max(self, other)
51+
}
52+
}
53+
54+
impl ops::BitAndAssign for Diverges {
55+
fn bitand_assign(&mut self, other: Self) {
56+
*self = *self & other;
57+
}
58+
}
59+
60+
impl ops::BitOrAssign for Diverges {
61+
fn bitor_assign(&mut self, other: Self) {
62+
*self = *self | other;
63+
}
64+
}
65+
66+
impl Diverges {
67+
/// Creates a `Diverges::Always` with the provided `span` and the default note message.
68+
pub(super) fn always(span: Span) -> Diverges {
69+
Diverges::Always { span, custom_note: None }
70+
}
71+
72+
pub(super) fn is_always(self) -> bool {
73+
// Enum comparison ignores the
74+
// contents of fields, so we just
75+
// fill them in with garbage here.
76+
self >= Diverges::Always { span: DUMMY_SP, custom_note: None }
77+
}
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
2+
use rustc_middle::ty::{self, Ty};
3+
use rustc_span::{self, Span};
4+
5+
use super::Expectation::*;
6+
use super::FnCtxt;
7+
8+
/// When type-checking an expression, we propagate downward
9+
/// whatever type hint we are able in the form of an `Expectation`.
10+
#[derive(Copy, Clone, Debug)]
11+
pub enum Expectation<'tcx> {
12+
/// We know nothing about what type this expression should have.
13+
NoExpectation,
14+
15+
/// This expression should have the type given (or some subtype).
16+
ExpectHasType(Ty<'tcx>),
17+
18+
/// This expression will be cast to the `Ty`.
19+
ExpectCastableToType(Ty<'tcx>),
20+
21+
/// This rvalue expression will be wrapped in `&` or `Box` and coerced
22+
/// to `&Ty` or `Box<Ty>`, respectively. `Ty` is `[A]` or `Trait`.
23+
ExpectRvalueLikeUnsized(Ty<'tcx>),
24+
}
25+
26+
impl<'a, 'tcx> Expectation<'tcx> {
27+
// Disregard "castable to" expectations because they
28+
// can lead us astray. Consider for example `if cond
29+
// {22} else {c} as u8` -- if we propagate the
30+
// "castable to u8" constraint to 22, it will pick the
31+
// type 22u8, which is overly constrained (c might not
32+
// be a u8). In effect, the problem is that the
33+
// "castable to" expectation is not the tightest thing
34+
// we can say, so we want to drop it in this case.
35+
// The tightest thing we can say is "must unify with
36+
// else branch". Note that in the case of a "has type"
37+
// constraint, this limitation does not hold.
38+
39+
// If the expected type is just a type variable, then don't use
40+
// an expected type. Otherwise, we might write parts of the type
41+
// when checking the 'then' block which are incompatible with the
42+
// 'else' branch.
43+
pub(super) fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
44+
match *self {
45+
ExpectHasType(ety) => {
46+
let ety = fcx.shallow_resolve(ety);
47+
if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation }
48+
}
49+
ExpectRvalueLikeUnsized(ety) => ExpectRvalueLikeUnsized(ety),
50+
_ => NoExpectation,
51+
}
52+
}
53+
54+
/// Provides an expectation for an rvalue expression given an *optional*
55+
/// hint, which is not required for type safety (the resulting type might
56+
/// be checked higher up, as is the case with `&expr` and `box expr`), but
57+
/// is useful in determining the concrete type.
58+
///
59+
/// The primary use case is where the expected type is a fat pointer,
60+
/// like `&[isize]`. For example, consider the following statement:
61+
///
62+
/// let x: &[isize] = &[1, 2, 3];
63+
///
64+
/// In this case, the expected type for the `&[1, 2, 3]` expression is
65+
/// `&[isize]`. If however we were to say that `[1, 2, 3]` has the
66+
/// expectation `ExpectHasType([isize])`, that would be too strong --
67+
/// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`.
68+
/// It is only the `&[1, 2, 3]` expression as a whole that can be coerced
69+
/// to the type `&[isize]`. Therefore, we propagate this more limited hint,
70+
/// which still is useful, because it informs integer literals and the like.
71+
/// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
72+
/// for examples of where this comes up,.
73+
pub(super) fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> {
74+
match fcx.tcx.struct_tail_without_normalization(ty).kind() {
75+
ty::Slice(_) | ty::Str | ty::Dynamic(..) => ExpectRvalueLikeUnsized(ty),
76+
_ => ExpectHasType(ty),
77+
}
78+
}
79+
80+
// Resolves `expected` by a single level if it is a variable. If
81+
// there is no expected type or resolution is not possible (e.g.,
82+
// no constraints yet present), just returns `None`.
83+
fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
84+
match self {
85+
NoExpectation => NoExpectation,
86+
ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(&t)),
87+
ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(&t)),
88+
ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(&t)),
89+
}
90+
}
91+
92+
pub(super) fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
93+
match self.resolve(fcx) {
94+
NoExpectation => None,
95+
ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty),
96+
}
97+
}
98+
99+
/// It sometimes happens that we want to turn an expectation into
100+
/// a **hard constraint** (i.e., something that must be satisfied
101+
/// for the program to type-check). `only_has_type` will return
102+
/// such a constraint, if it exists.
103+
pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option<Ty<'tcx>> {
104+
match self.resolve(fcx) {
105+
ExpectHasType(ty) => Some(ty),
106+
NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None,
107+
}
108+
}
109+
110+
/// Like `only_has_type`, but instead of returning `None` if no
111+
/// hard constraint exists, creates a fresh type variable.
112+
pub(super) fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> {
113+
self.only_has_type(fcx).unwrap_or_else(|| {
114+
fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span })
115+
})
116+
}
117+
}

0 commit comments

Comments
 (0)