mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-28 09:44:08 +00:00
internal: Normalize field type after substituting
This commit is contained in:
parent
1280961b51
commit
b17aefb83a
@ -285,6 +285,7 @@ impl ExprValidator {
|
||||
let pattern_arena = Arena::new();
|
||||
let cx = MatchCheckCtx {
|
||||
module: self.owner.module(db.upcast()),
|
||||
body: self.owner,
|
||||
db,
|
||||
pattern_arena: &pattern_arena,
|
||||
};
|
||||
|
@ -53,7 +53,7 @@ use smallvec::{smallvec, SmallVec};
|
||||
use stdx::never;
|
||||
use syntax::SmolStr;
|
||||
|
||||
use crate::{AdtId, Interner, Scalar, Ty, TyExt, TyKind};
|
||||
use crate::{infer::normalize, AdtId, Interner, Scalar, Ty, TyExt, TyKind};
|
||||
|
||||
use super::{
|
||||
usefulness::{helper::Captures, MatchCheckCtx, PatCtxt},
|
||||
@ -753,8 +753,8 @@ impl<'p> Fields<'p> {
|
||||
let fields_len = variant.variant_data(cx.db.upcast()).fields().len() as u32;
|
||||
|
||||
(0..fields_len).map(|idx| LocalFieldId::from_raw(idx.into())).filter_map(move |fid| {
|
||||
// TODO check ty has been normalized
|
||||
let ty = field_ty[fid].clone().substitute(Interner, substs);
|
||||
let ty = normalize(cx.db, cx.body, ty);
|
||||
let is_visible = matches!(adt, hir_def::AdtId::EnumId(..))
|
||||
|| visibility[fid].is_visible_from(cx.db.upcast(), cx.module);
|
||||
let is_uninhabited = cx.is_uninhabited(&ty);
|
||||
|
@ -273,7 +273,7 @@
|
||||
|
||||
use std::iter::once;
|
||||
|
||||
use hir_def::{AdtId, HasModule, ModuleId};
|
||||
use hir_def::{AdtId, DefWithBodyId, HasModule, ModuleId};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use typed_arena::Arena;
|
||||
|
||||
@ -285,6 +285,7 @@ use self::{helper::Captures, ArmType::*, Usefulness::*};
|
||||
|
||||
pub(crate) struct MatchCheckCtx<'a, 'p> {
|
||||
pub(crate) module: ModuleId,
|
||||
pub(crate) body: DefWithBodyId,
|
||||
pub(crate) db: &'a dyn HirDatabase,
|
||||
/// Lowered patterns from arms plus generated by the check.
|
||||
pub(crate) pattern_arena: &'p Arena<DeconstructedPat<'p>>,
|
||||
|
@ -16,7 +16,7 @@
|
||||
use std::ops::Index;
|
||||
use std::sync::Arc;
|
||||
|
||||
use chalk_ir::{cast::Cast, DebruijnIndex, Mutability, Safety, Scalar};
|
||||
use chalk_ir::{cast::Cast, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
|
||||
use hir_def::{
|
||||
body::Body,
|
||||
data::{ConstData, FunctionData, StaticData},
|
||||
@ -70,6 +70,26 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
|
||||
Arc::new(ctx.resolve_all())
|
||||
}
|
||||
|
||||
/// Fully normalize all the types found within `ty` in context of `owner` body definition.
|
||||
///
|
||||
/// This is appropriate to use only after type-check: it assumes
|
||||
/// that normalization will succeed, for example.
|
||||
pub(crate) fn normalize(db: &dyn HirDatabase, owner: DefWithBodyId, ty: Ty) -> Ty {
|
||||
if !ty.data(Interner).flags.intersects(TypeFlags::HAS_PROJECTION) {
|
||||
return ty;
|
||||
}
|
||||
let krate = owner.module(db.upcast()).krate();
|
||||
let trait_env = owner
|
||||
.as_generic_def_id()
|
||||
.map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d));
|
||||
let mut table = unify::InferenceTable::new(db, trait_env.clone());
|
||||
|
||||
let ty_with_vars = table.normalize_associated_types_in(ty);
|
||||
table.resolve_obligations_as_possible();
|
||||
table.propagate_diverging_flag();
|
||||
table.resolve_completely(ty_with_vars)
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
enum ExprOrPatId {
|
||||
ExprId(ExprId),
|
||||
|
@ -863,6 +863,30 @@ fn main() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normalize_field_ty() {
|
||||
check_diagnostics_no_bails(
|
||||
r"
|
||||
trait Trait { type Projection; }
|
||||
enum E {Foo, Bar}
|
||||
struct A;
|
||||
impl Trait for A { type Projection = E; }
|
||||
struct Next<T: Trait>(T::Projection);
|
||||
static __: () = {
|
||||
let n: Next<A> = Next(E::Foo);
|
||||
match n { Next(E::Foo) => {} }
|
||||
// ^ error: missing match arm
|
||||
match n { Next(E::Foo | E::Bar) => {} }
|
||||
match n { Next(E::Foo | _ ) => {} }
|
||||
match n { Next(_ | E::Bar) => {} }
|
||||
match n { _ | Next(E::Bar) => {} }
|
||||
match &n { Next(E::Foo | E::Bar) => {} }
|
||||
match &n { _ | Next(E::Bar) => {} }
|
||||
};",
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
mod false_negatives {
|
||||
//! The implementation of match checking here is a work in progress. As we roll this out, we
|
||||
//! prefer false negatives to false positives (ideally there would be no false positives). This
|
||||
|
Loading…
Reference in New Issue
Block a user