Skip to content

Commit

Permalink
Merge pull request #524 from doctorn/adt-refactor
Browse files Browse the repository at this point in the history
Support for ADTs
  • Loading branch information
jackh726 committed Jul 2, 2020
2 parents cab0530 + bf5224e commit 6a9fc66
Show file tree
Hide file tree
Showing 19 changed files with 681 additions and 105 deletions.
2 changes: 1 addition & 1 deletion chalk-integration/src/lib.rs
Expand Up @@ -18,7 +18,7 @@ pub use interner::{Identifier, RawId};

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum TypeSort {
Struct,
Adt,
FnDef,
Closure,
Trait,
Expand Down
38 changes: 28 additions & 10 deletions chalk-integration/src/lowering.rs
Expand Up @@ -370,7 +370,7 @@ impl LowerProgram for Program {

for (item, &raw_id) in self.items.iter().zip(&raw_ids) {
match item {
Item::StructDefn(defn) => {
Item::AdtDefn(defn) => {
let type_kind = defn.lower_type_kind()?;
let id = AdtId(raw_id);
adt_ids.insert(type_kind.name.clone(), id);
Expand Down Expand Up @@ -444,7 +444,7 @@ impl LowerProgram for Program {
};

match *item {
Item::StructDefn(ref d) => {
Item::AdtDefn(ref d) => {
let adt_id = AdtId(raw_id);
adt_data.insert(adt_id, Arc::new(d.lower_adt(adt_id, &empty_env)?));
adt_reprs.insert(adt_id, d.lower_adt_repr()?);
Expand Down Expand Up @@ -720,7 +720,7 @@ trait LowerParameterMap {
}
}

impl LowerParameterMap for StructDefn {
impl LowerParameterMap for AdtDefn {
fn synthetic_parameters(&self) -> Option<chalk_ir::WithKind<ChalkIr, Ident>> {
None
}
Expand Down Expand Up @@ -853,11 +853,11 @@ trait LowerWhereClauses {
}
}

impl LowerTypeKind for StructDefn {
impl LowerTypeKind for AdtDefn {
fn lower_type_kind(&self) -> LowerResult<TypeKind> {
let interner = &ChalkIr;
Ok(TypeKind {
sort: TypeSort::Struct,
sort: TypeSort::Adt,
name: self.name.str.clone(),
binders: chalk_ir::Binders::new(
chalk_ir::VariableKinds::from(interner, self.all_parameters().anonymize()),
Expand Down Expand Up @@ -901,7 +901,7 @@ impl LowerTypeKind for ClosureDefn {
}
}

impl LowerWhereClauses for StructDefn {
impl LowerWhereClauses for AdtDefn {
fn where_clauses(&self) -> &[QuantifiedWhereClause] {
&self.where_clauses
}
Expand Down Expand Up @@ -1094,9 +1094,18 @@ trait LowerAdtDefn {
adt_id: chalk_ir::AdtId<ChalkIr>,
env: &Env,
) -> LowerResult<rust_ir::AdtDatum<ChalkIr>>;

fn lower_adt_variant(
&self,
variant: &Variant,
env: &Env,
) -> LowerResult<rust_ir::AdtVariantDatum<ChalkIr>> {
let fields: LowerResult<_> = variant.fields.iter().map(|f| f.ty.lower(env)).collect();
Ok(rust_ir::AdtVariantDatum { fields: fields? })
}
}

impl LowerAdtDefn for StructDefn {
impl LowerAdtDefn for AdtDefn {
fn lower_adt(
&self,
adt_id: chalk_ir::AdtId<ChalkIr>,
Expand All @@ -1109,11 +1118,15 @@ impl LowerAdtDefn for StructDefn {
}

let binders = env.in_binders(self.all_parameters(), |env| {
let fields: LowerResult<_> = self.fields.iter().map(|f| f.ty.lower(env)).collect();
let variants: LowerResult<_> = self
.variants
.iter()
.map(|v| self.lower_adt_variant(v, env))
.collect();
let where_clauses = self.lower_where_clauses(env)?;

Ok(rust_ir::AdtDatumBound {
fields: fields?,
variants: variants?,
where_clauses,
})
})?;
Expand All @@ -1128,6 +1141,11 @@ impl LowerAdtDefn for StructDefn {
id: adt_id,
binders,
flags,
kind: match self.flags.kind {
AdtKind::Struct => rust_ir::AdtKind::Struct,
AdtKind::Enum => rust_ir::AdtKind::Enum,
AdtKind::Union => rust_ir::AdtKind::Union,
},
})
}
}
Expand All @@ -1136,7 +1154,7 @@ trait LowerAdtRepr {
fn lower_adt_repr(&self) -> LowerResult<rust_ir::AdtRepr>;
}

impl LowerAdtRepr for StructDefn {
impl LowerAdtRepr for AdtDefn {
fn lower_adt_repr(&self) -> LowerResult<rust_ir::AdtRepr> {
Ok(rust_ir::AdtRepr {
repr_c: self.repr.repr_c,
Expand Down
4 changes: 2 additions & 2 deletions chalk-ir/src/interner.rs
@@ -1,5 +1,4 @@
//! Encapsulates the concrete representation of core types such as types and goals.

use crate::AdtId;
use crate::AliasTy;
use crate::ApplicationTy;
Expand Down Expand Up @@ -196,7 +195,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash {
}

/// Prints the debug representation of a type-kind-id.
/// Returns `None` to fallback to the default debug output.
/// Returns `None` to fallback to the default debug output (e.g.,
/// if no info about current program is available from TLS).
#[allow(unused_variables)]
fn debug_trait_id(
trait_id: TraitId<Self>,
Expand Down
26 changes: 20 additions & 6 deletions chalk-parse/src/ast.rs
Expand Up @@ -20,7 +20,7 @@ pub struct Program {

#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Item {
StructDefn(StructDefn),
AdtDefn(AdtDefn),
FnDefn(FnDefn),
ClosureDefn(ClosureDefn),
TraitDefn(TraitDefn),
Expand All @@ -30,24 +30,38 @@ pub enum Item {
}

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct StructDefn {
pub struct AdtDefn {
pub name: Identifier,
pub variable_kinds: Vec<VariableKind>,
pub where_clauses: Vec<QuantifiedWhereClause>,
pub variants: Vec<Variant>,
pub flags: AdtFlags,
pub repr: AdtRepr,
}

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Variant {
pub name: Identifier,
pub fields: Vec<Field>,
pub flags: StructFlags,
pub repr: StructRepr,
}

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct StructFlags {
pub struct AdtFlags {
pub upstream: bool,
pub fundamental: bool,
pub phantom_data: bool,
pub kind: AdtKind,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum AdtKind {
Struct,
Enum,
Union,
}

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct StructRepr {
pub struct AdtRepr {
pub repr_c: bool,
pub repr_packed: bool,
}
Expand Down
72 changes: 63 additions & 9 deletions chalk-parse/src/parser.lalrpop
Expand Up @@ -13,7 +13,7 @@ Items: Vec<Item> = {

Item: Option<Item> = {
Comment => None,
StructDefn => Some(Item::StructDefn(<>)),
AdtDefn => Some(Item::AdtDefn(<>)),
FnDefn => Some(Item::FnDefn(<>)),
ClosureDefn => Some(Item::ClosureDefn(<>)),
TraitDefn => Some(Item::TraitDefn(<>)),
Expand Down Expand Up @@ -59,29 +59,82 @@ WellKnownTrait: WellKnownTrait = {
"#" "[" "lang" "(" "unsize" ")" "]" => WellKnownTrait::Unsize,
};

StructRepr: Atom = "#" "[" "repr" "(" <name:Id> ")" "]" => name.str;
AdtRepr: Atom = "#" "[" "repr" "(" <name:Id> ")" "]" => name.str;

StructDefn: StructDefn = {
<upstream:UpstreamKeyword?> <fundamental:FundamentalKeyword?> <phantom_data:PhantomDataKeyword?> <repr:StructRepr*>
AdtDefn: AdtDefn = {
<upstream:UpstreamKeyword?> <fundamental:FundamentalKeyword?> <phantom_data:PhantomDataKeyword?> <repr:AdtRepr*>
"enum" <n:Id><p:Angle<VariableKind>>
<w:QuantifiedWhereClauses> "{" <v:Variants> "}" => AdtDefn
{
name: n,
variable_kinds: p,
where_clauses: w,
variants: v,
flags: AdtFlags {
upstream: upstream.is_some(),
fundamental: fundamental.is_some(),
phantom_data: phantom_data.is_some(),
kind: AdtKind::Enum,
},
repr: AdtRepr {
repr_c: repr.iter().any(|s| s == "C"),
repr_packed: repr.iter().any(|s| s == "packed"),
},
},
<upstream:UpstreamKeyword?> <fundamental:FundamentalKeyword?> <phantom_data:PhantomDataKeyword?> <repr:AdtRepr*>
"struct" <n:Id><p:Angle<VariableKind>>
<w:QuantifiedWhereClauses> "{" <f:Fields> "}" => StructDefn
<w:QuantifiedWhereClauses> "{" <f:Fields> "}" => AdtDefn
{
variants: vec![Variant {
// FIXME(#505) choose a proper span
name: Identifier {
str: Atom::from("0"),
span: n.span,
},
fields: f,
}],
name: n,
variable_kinds: p,
where_clauses: w,
fields: f,
flags: StructFlags {
flags: AdtFlags {
upstream: upstream.is_some(),
fundamental: fundamental.is_some(),
phantom_data: phantom_data.is_some(),
kind: AdtKind::Struct,
},
repr: StructRepr {
repr: AdtRepr {
repr_c: repr.iter().any(|s| s == "C"),
repr_packed: repr.iter().any(|s| s == "packed"),
},
}
};

Variants: Vec<Variant> = {
<Comma<Variant>>,
};

Variant: Variant = {
<n: Id> "{" <f:Fields> "}" => Variant {
name: n,
fields: f,
},
<n: Id> "(" <tys:Comma<Ty>> ")" => Variant {
fields: tys.into_iter().enumerate().map(|(i, t)| Field {
// FIXME(#505) choose a proper span
name: Identifier {
str: Atom::from(format!("{}", i)),
span: n.span,
},
ty: t,
}).collect(),
name: n,
},
<n: Id> => Variant {
name: n,
fields: vec![],
},
};

FnReturn: Ty = {
"->" <ty:Ty> => ty,
};
Expand Down Expand Up @@ -497,7 +550,8 @@ Separator1<S, T>: Vec<T> = {

#[inline]
Comma<T>: Vec<T> = {
<Separator<",", T>>
<v:Separator<",", T>> "," => v,
<v:Separator<",", T>> => v,
};

#[inline]
Expand Down
13 changes: 8 additions & 5 deletions chalk-solve/src/clauses.rs
Expand Up @@ -18,6 +18,7 @@ mod env_elaborator;
mod generalize;
pub mod program_clauses;

/// FIXME(#505) update comments for ADTs
/// For auto-traits, we generate a default rule for every struct,
/// unless there is a manual impl for that struct given explicitly.
///
Expand Down Expand Up @@ -74,8 +75,8 @@ pub fn push_auto_trait_impls<I: Interner>(
return;
}

let binders = adt_datum.binders.map_ref(|b| &b.fields);
builder.push_binders(&binders, |builder, fields| {
let binders = adt_datum.binders.map_ref(|b| &b.variants);
builder.push_binders(&binders, |builder, variants| {
let self_ty: Ty<_> = ApplicationTy {
name: adt_id.cast(interner),
substitution: builder.substitution_in_scope(),
Expand All @@ -96,9 +97,11 @@ pub fn push_auto_trait_impls<I: Interner>(
// }
builder.push_clause(
auto_trait_ref,
fields.iter().map(|field_ty| TraitRef {
trait_id: auto_trait_id,
substitution: Substitution::from1(interner, field_ty.clone()),
variants.iter().flat_map(|variant| {
variant.fields.iter().map(|field_ty| TraitRef {
trait_id: auto_trait_id,
substitution: Substitution::from1(interner, field_ty.clone()),
})
}),
);
});
Expand Down
16 changes: 10 additions & 6 deletions chalk-solve/src/clauses/builtin_traits/sized.rs
Expand Up @@ -2,6 +2,7 @@ use std::iter;

use crate::clauses::builtin_traits::needs_impl_for_tys;
use crate::clauses::ClauseBuilder;
use crate::rust_ir::AdtKind;
use crate::{Interner, RustIrDatabase, TraitRef};
use chalk_ir::{AdtId, ApplicationTy, Substitution, TyData, TypeName};

Expand All @@ -14,22 +15,25 @@ fn push_adt_sized_conditions<I: Interner>(
) {
let adt_datum = db.adt_datum(adt_id);

// ADTs with no fields are always Sized
if adt_datum.binders.skip_binders().fields.is_empty() {
// WF ensures that all enums are Sized, so we only have to consider structs.
if adt_datum.kind != AdtKind::Struct {
builder.push_fact(trait_ref.clone());
return;
}

let interner = db.interner();

// To check if an ADT type S<..> is Sized, we only have to look at its last field.
// To check if a struct S<..> is Sized, we only have to look at its last field.
// This is because the WF checks for ADTs require that all the other fields must be Sized.
let last_field_ty = adt_datum
.binders
.map_ref(|b| b.fields.last().unwrap())
.substitute(interner, substitution);
.map_ref(|b| &b.variants)
.substitute(interner, substitution)
.into_iter()
.take(1) // We have a struct so we're guaranteed one variant
.flat_map(|mut v| v.fields.pop());

needs_impl_for_tys(db, builder, trait_ref, iter::once(last_field_ty));
needs_impl_for_tys(db, builder, trait_ref, last_field_ty);
}

fn push_tuple_sized_conditions<I: Interner>(
Expand Down

0 comments on commit 6a9fc66

Please sign in to comment.