Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enum variant support #89745

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,22 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
PlaceTy { ty: base_ty, variant_index: Some(index) }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we'd remove the variant_index field and replace ty here with the variant type

}
}
ty::Variant(ty, _) => match ty.kind() {
ty::Adt(adt_def, _substs) if adt_def.is_enum() => {
if index.as_usize() >= adt_def.variants.len() {
PlaceTy::from_ty(span_mirbug_and_err!(
self,
place,
"cast to variant #{:?} but enum only has {:?}",
index,
adt_def.variants.len()
))
} else {
PlaceTy { ty: *ty, variant_index: Some(index) }
}
}
_ => bug!("unexpected type: {:?}", ty.kind()),
},
Comment on lines +747 to +762
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is downcasting a variant type an operation we would ever encounter?

I think for now this arm can just mir-bug if index != var_index where var_index is the second field of ty::Variant.

that would allow re-downcasting to the same variant, but nothing else

// We do not need to handle generators here, because this runs
// before the generator transform stage.
_ => {
Expand Down Expand Up @@ -812,6 +828,12 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
let (variant, substs) = match base_ty {
PlaceTy { ty, variant_index: Some(variant_index) } => match *ty.kind() {
ty::Adt(adt_def, substs) => (&adt_def.variants[variant_index], substs),
ty::Variant(ty, _) => match ty.kind() {
ty::Adt(adt_def, substs) => {
(adt_def.variants.get(variant_index).expect(""), *substs)
}
_ => bug!("unexpected type: {:?}", ty.kind()),
},
Comment on lines 829 to +836
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we get rid of variant_index as mentioned earlier, then we can grab the variant index from the ty::Variant

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we remove variant_index how would we handle the Adt match arm above?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the above comment is implemented, then we should never encounter that arm, it should always be ty::Variant if we would have had a variant index in the PlaceTy

ty::Generator(def_id, substs, _) => {
let mut variants = substs.as_generator().state_tys(def_id, tcx);
let mut variant = match variants.nth(variant_index.into()) {
Expand All @@ -833,6 +855,12 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
ty::Adt(adt_def, substs) if !adt_def.is_enum() => {
(&adt_def.variants[VariantIdx::new(0)], substs)
}
ty::Variant(ty, _) => match ty.kind() {
ty::Adt(adt_def, substs) if adt_def.is_enum() => {
(&adt_def.variants[VariantIdx::new(0)], *substs)
}
_ => bug!("unexpected type: {:?}", ty.kind()),
},
ty::Closure(_, substs) => {
return match substs
.as_closure()
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 @@ -373,6 +373,7 @@ fn push_debuginfo_type_name<'tcx>(
t
);
}
ty::Variant(..) => unimplemented!("TODO(zhamlin)"),
}

/// MSVC names enums differently than other platforms so that the debugging visualization
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/const_eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ fn const_to_valtree_inner<'tcx>(
| ty::Closure(..)
| ty::Generator(..)
| ty::GeneratorWitness(..) => None,
ty::Variant(..) => unimplemented!("TODO(zhamlin)"),
}
}

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 @@ -100,6 +100,7 @@ crate fn eval_nullary_intrinsic<'tcx>(
| ty::Never
| ty::Tuple(_)
| ty::Error(_) => ConstValue::from_machine_usize(0u64, &tcx),
ty::Variant(..) => unimplemented!("TODO(zhamlin)"),
},
other => bug!("`{}` is not a zero arg intrinsic", other),
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
ty::Foreign(def_id) => self.print_def_path(def_id, &[]),

ty::GeneratorWitness(_) => bug!("type_name: unexpected `GeneratorWitness`"),
ty::Variant(..) => unimplemented!("TODO(zhamlin)"),
}
}

Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_const_eval/src/interpret/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let discr_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
let discr_bits = discr_val.assert_bits(discr_layout.size);
// Convert discriminant to variant index, and catch invalid discriminants.
let index = match *op.layout.ty.kind() {
let index = match *op.layout.ty.strip_variant_type().kind() {
ty::Adt(adt, _) => {
adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits)
}
Expand All @@ -693,6 +693,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
.discriminants(def_id, *self.tcx)
.find(|(_, var)| var.val == discr_bits)
}
ty::Variant(..) => unreachable!(),
_ => span_bug!(self.cur_span(), "tagged layout for non-adt non-generator"),
}
.ok_or_else(|| err_ub!(InvalidTag(Scalar::from_uint(tag_bits, tag_layout.size))))?;
Expand Down
13 changes: 8 additions & 5 deletions compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
match layout.variants {
Variants::Multiple { tag_field, .. } => {
if tag_field == field {
return match layout.ty.kind() {
return match layout.ty.strip_variant_type().kind() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variant types should never have Variants::Multiple layout so this should be unreachable.

Generally I am not very happy with strip_variant_type, from a conceptual perspective this rarely seems like the right thing to do -- but maybe my intuition is leading me astray here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strip_variant_type is the correct thing wherever we don't actually handle variant things on generators or adts right now, so here it is indeed wrong, we should not ever encounter adt/generator anymore, but for that Layout::for_variant needs to be fixed to return ty::Variant.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

layout is the outer layout of the enum here, why should we not encounter adt/generators here?

It's the other match below in the same function where we should not encounter them any more.

ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag,
ty::Generator(..) => PathElem::GeneratorTag,
_ => bug!("non-variant type {:?}", layout.ty),
Expand All @@ -228,7 +228,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
}

// Now we know we are projecting to a field, so figure out which one.
match layout.ty.kind() {
match layout.ty.strip_variant_type().kind() {
// generators and closures.
ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
let mut name = None;
Expand Down Expand Up @@ -495,7 +495,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
) -> InterpResult<'tcx, bool> {
// Go over all the primitive types
let ty = value.layout.ty;
match ty.kind() {
match ty.strip_variant_type().kind() {
ty::Bool => {
let value = self.read_scalar(value)?;
try_validation!(
Expand Down Expand Up @@ -612,6 +612,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
| ty::Opaque(..)
| ty::Projection(..)
| ty::GeneratorWitness(..) => bug!("Encountered invalid type {:?}", ty),

ty::Variant(..) => unreachable!(),
}
}

Expand Down Expand Up @@ -727,11 +729,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
variant_id: VariantIdx,
new_op: &OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
let name = match old_op.layout.ty.kind() {
let ty = old_op.layout.ty.strip_variant_type();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variant types don't have variants, so something seems wrong if we see a variant type here.

let name = match ty.kind() {
ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].ident.name),
// Generators also have variants
ty::Generator(..) => PathElem::GeneratorState(variant_id),
_ => bug!("Unexpected type with variant: {:?}", old_op.layout.ty),
_ => bug!("Unexpected type with variant: {:?}", ty),
};
self.with_elem(name, move |this| this.visit_value(new_op))
}
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 @@ -385,6 +385,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
| ty::Uint(..)
| ty::Float(..)
| ty::Adt(..)
| ty::Variant(..)
| ty::Str
| ty::Error(_)
| ty::Array(..)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_infer/src/infer/freshen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
| ty::Uint(..)
| ty::Float(..)
| ty::Adt(..)
| ty::Variant(..)
| ty::Str
| ty::Error(_)
| ty::Array(..)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_lint/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1130,6 +1130,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
| ty::GeneratorWitness(..)
| ty::Placeholder(..)
| ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty),
ty::Variant(..) => unimplemented!("TODO(zhamlin)"),
}
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ impl<'tcx> CastTy<'tcx> {
ty::Uint(u) => Some(CastTy::Int(IntTy::U(u))),
ty::Float(_) => Some(CastTy::Float),
ty::Adt(d, _) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)),
ty::Variant(ty, _) => Self::from_ty(ty),
ty::RawPtr(mt) => Some(CastTy::Ptr(mt)),
ty::FnPtr(..) => Some(CastTy::FnPtr),
_ => None,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ macro_rules! impl_decodable_via_ref {
})*
}
}

// TODO(zhamlin): enum variant here?
impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::AdtDef {
fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
let def_id = <DefId as Decodable<D>>::decode(decoder)?;
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1919,6 +1919,7 @@ impl<'tcx> TyCtxt<'tcx> {
fmt,
self.0,
Adt,
Variant,
Array,
Slice,
RawPtr,
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_middle/src/ty/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ impl<'tcx> ty::TyS<'tcx> {
ty::Tuple(ref tys) if tys.is_empty() => format!("`{}`", self).into(),

ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.def_path_str(def.did)).into(),
ty::Variant(ty, _) => ty.sort_string(tcx),
ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(),
ty::Array(t, n) => {
if t.is_simple_ty() {
Expand Down Expand Up @@ -315,6 +316,10 @@ impl<'tcx> ty::TyS<'tcx> {
| ty::Never => "type".into(),
ty::Tuple(ref tys) if tys.is_empty() => "unit type".into(),
ty::Adt(def, _) => def.descr().into(),
ty::Variant(ty, _) => match ty.kind() {
ty::Adt(def, _) => format!("{} variant", def.descr()).into(),
_ => bug!("unexpected type: {:?}", ty.kind()),
},
ty::Foreign(_) => "extern type".into(),
ty::Array(..) => "array".into(),
ty::Slice(_) => "slice".into(),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/fast_reject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ pub fn simplify_type(
ty::Uint(uint_type) => Some(UintSimplifiedType(uint_type)),
ty::Float(float_type) => Some(FloatSimplifiedType(float_type)),
ty::Adt(def, _) => Some(AdtSimplifiedType(def.did)),
ty::Variant(ty, _) => simplify_type(tcx, ty, can_simplify_params),
ty::Str => Some(StrSimplifiedType),
ty::Array(..) | ty::Slice(_) => Some(ArraySimplifiedType),
ty::RawPtr(_) => Some(PtrSimplifiedType),
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/ty/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ impl FlagComputation {
self.add_substs(substs);
}

&ty::Variant(ty, _) => self.add_kind(ty.kind()),

&ty::Projection(data) => {
self.add_flags(TypeFlags::HAS_TY_PROJECTION);
self.add_projection_ty(data);
Expand Down
20 changes: 20 additions & 0 deletions compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1394,6 +1394,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
tcx.intern_layout(best_layout)
}

ty::Variant(ty, _) => self.layout_of_uncached(ty)?,

// Types with no meaningful known layout.
ty::Projection(_) | ty::Opaque(..) => {
// NOTE(eddyb) `layout_of` query should've normalized these away,
Expand Down Expand Up @@ -2386,6 +2388,24 @@ where
}
}

ty::Variant(ty, _) => match ty.kind() {
ty::Adt(def, substs) => match this.variants {
Variants::Single { index } => {
return TyMaybeWithLayout::Ty(
def.variants[index].fields[i].ty(tcx, substs),
);
}

// Discriminant field for enums (where applicable).
Variants::Multiple { tag, .. } => {
// TODO(zhamlin): make this work
assert_eq!(i, 0);
return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
}
},
_ => bug!("unexpected type: {:?}", ty.kind()),
},

ty::Projection(_)
| ty::Bound(..)
| ty::Placeholder(..)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/outlives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ fn compute_components(
ty::Float(..) | // OutlivesScalar
ty::Never | // ...
ty::Adt(..) | // OutlivesNominalType
ty::Variant(..) | // OutlivesNominalType
ty::Opaque(..) | // OutlivesNominalType (ish)
ty::Foreign(..) | // OutlivesNominalType
ty::Str | // OutlivesScalar (ish)
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 @@ -315,6 +315,7 @@ fn characteristic_def_id_of_type_cached<'a>(
| ty::GeneratorWitness(..)
| ty::Never
| ty::Float(_) => None,
ty::Variant(..) => unimplemented!("TODO(zhamlin)"),
}
}
pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,14 @@ pub trait PrettyPrinter<'tcx>:
ty::Adt(def, substs) => {
p!(print_def_path(def.did, substs));
}

ty::Variant(ty, idx) => match ty.kind() {
ty::Adt(def, substs) => {
p!(print_def_path(def.did, substs));
p!(write("::{}", def.variants.get(idx).unwrap().ident.name));
}
_ => bug!("unexpected type: {:?}", ty.kind()),
},
ty::Dynamic(data, r) => {
let print_r = self.region_should_not_be_omitted(r);
if print_r {
Expand Down
24 changes: 24 additions & 0 deletions compiler/rustc_middle/src/ty/relate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,30 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>(
Ok(tcx.mk_adt(a_def, substs))
}

// TODO(zhamlin): handle this somewhere else?
// Enum <- Enum Variant
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the site for relating things that have no order in their equality. So you should not compare variants with anything other than variants here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the right place to do this is to add an arm (and a function, like in the other arms) for ty::Variant here:

(&ty::Adt(a_def, a_substs), &ty::Variant(b_ty, _)) if relation.a_is_expected() => {
match b_ty.kind() {
ty::Adt(b_def, b_substs) if a_def == *b_def => {
let substs = relation.relate_item_substs(a_def.did, a_substs, b_substs)?;
Ok(tcx.mk_adt(a_def, substs))
}
_ => Err(TypeError::Sorts(expected_found(relation, a, b))),
}
}

(&ty::Variant(a_ty, _), &ty::Adt(b_def, b_substs)) => match a_ty.kind() {
ty::Adt(a_def, a_substs) if *a_def == b_def => {
let substs = relation.relate_item_substs(a_def.did, a_substs, b_substs)?;
Ok(tcx.mk_adt(a_def, substs))
}
_ => Err(TypeError::Sorts(expected_found(relation, a, b))),
},

(&ty::Variant(a_ty, a_idx), &ty::Variant(b_ty, b_idx)) if a_idx == b_idx => {
relation.relate(a_ty, b_ty).map(|ty| tcx.mk_ty(ty::Variant(ty, a_idx)))
}

(&ty::Foreign(a_id), &ty::Foreign(b_id)) if a_id == b_id => Ok(tcx.mk_foreign(a_id)),

(&ty::Dynamic(a_obj, a_region), &ty::Dynamic(b_obj, b_region)) => {
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 @@ -871,6 +871,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)),
ty::Slice(typ) => ty::Slice(typ.fold_with(folder)),
ty::Adt(tid, substs) => ty::Adt(tid, substs.fold_with(folder)),
ty::Variant(ty, idx) => ty::Variant(ty.fold_with(folder), idx),
ty::Dynamic(trait_ty, region) => {
ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder))
}
Expand Down Expand Up @@ -917,6 +918,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
}
ty::Slice(typ) => typ.visit_with(visitor),
ty::Adt(_, substs) => substs.visit_with(visitor),
ty::Variant(ty, _idx) => ty.visit_with(visitor),
ty::Dynamic(ref trait_ty, ref reg) => {
trait_ty.visit_with(visitor)?;
reg.visit_with(visitor)
Expand Down
Loading