Skip to content

Commit

Permalink
Merge pull request #481 from Mcat12/feature/function-abi
Browse files Browse the repository at this point in the history
Model function ABI in the Rust IR
  • Loading branch information
nikomatsakis authored Jun 10, 2020
2 parents 5b6ef58 + 48cb467 commit bf33634
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 14 deletions.
3 changes: 3 additions & 0 deletions chalk-integration/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::interner::ChalkIr;
use chalk_parse::ast::{Identifier, Kind};
use chalk_solve::coherence::CoherenceError;
use chalk_solve::wf::WfError;
use string_cache::DefaultAtom as Atom;

/// Wrapper type for the various errors that can occur during chalk
/// processing.
Expand Down Expand Up @@ -91,6 +92,7 @@ pub enum RustIrError {
actual: Kind,
},
CannotApplyTypeParameter(Identifier),
InvalidExternAbi(Atom),
}

impl std::fmt::Display for RustIrError {
Expand Down Expand Up @@ -183,6 +185,7 @@ impl std::fmt::Display for RustIrError {
RustIrError::CannotApplyTypeParameter(name) => {
write!(f, "cannot apply type parameter `{}`", name)
}
RustIrError::InvalidExternAbi(abi) => write!(f, "invalid extern ABI `{}`", abi),
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions chalk-integration/src/interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ impl Debug for RawId {
}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum ChalkFnAbi {
Rust,
C,
}

/// The default "interner" and the only interner used by chalk
/// itself. In this interner, no interning actually occurs.
#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
Expand All @@ -50,6 +56,7 @@ impl Interner for ChalkIr {
type DefId = RawId;
type InternedAdtId = RawId;
type Identifier = Identifier;
type FnAbi = ChalkFnAbi;

fn debug_adt_id(
type_kind_id: AdtId<ChalkIr>,
Expand Down
34 changes: 30 additions & 4 deletions chalk-integration/src/lowering.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::interner::ChalkIr;
use crate::interner::{ChalkFnAbi, ChalkIr};
use chalk_ir::cast::{Cast, Caster};
use chalk_ir::interner::HasInterner;
use chalk_ir::interner::{HasInterner, Interner};
use chalk_ir::{
self, AdtId, AssocTypeId, BoundVar, ClausePriority, DebruijnIndex, FnDefId, ImplId, OpaqueTyId,
QuantifiedWhereClauses, Substitution, ToGenericArg, TraitId, TyKind,
Expand All @@ -24,6 +24,7 @@ type TraitIds = BTreeMap<Ident, chalk_ir::TraitId<ChalkIr>>;
type OpaqueTyIds = BTreeMap<Ident, chalk_ir::OpaqueTyId<ChalkIr>>;
type AdtKinds = BTreeMap<chalk_ir::AdtId<ChalkIr>, TypeKind>;
type FnDefKinds = BTreeMap<chalk_ir::FnDefId<ChalkIr>, TypeKind>;
type FnDefAbis = BTreeMap<FnDefId<ChalkIr>, <ChalkIr as Interner>::FnAbi>;
type TraitKinds = BTreeMap<chalk_ir::TraitId<ChalkIr>, TypeKind>;
type OpaqueTyKinds = BTreeMap<chalk_ir::OpaqueTyId<ChalkIr>, TypeKind>;
type AssociatedTyLookups = BTreeMap<(chalk_ir::TraitId<ChalkIr>, Ident), AssociatedTyLookup>;
Expand All @@ -40,6 +41,7 @@ struct Env<'k> {
adt_kinds: &'k AdtKinds,
fn_def_ids: &'k FnDefIds,
fn_def_kinds: &'k FnDefKinds,
fn_def_abis: &'k FnDefAbis,
trait_ids: &'k TraitIds,
trait_kinds: &'k TraitKinds,
opaque_ty_ids: &'k OpaqueTyIds,
Expand Down Expand Up @@ -320,6 +322,7 @@ impl LowerProgram for Program {
let mut opaque_ty_ids = BTreeMap::new();
let mut adt_kinds = BTreeMap::new();
let mut fn_def_kinds = BTreeMap::new();
let mut fn_def_abis = BTreeMap::new();
let mut trait_kinds = BTreeMap::new();
let mut opaque_ty_kinds = BTreeMap::new();
let mut object_safe_traits = HashSet::new();
Expand All @@ -336,6 +339,7 @@ impl LowerProgram for Program {
let id = FnDefId(raw_id);
fn_def_ids.insert(type_kind.name.clone(), id);
fn_def_kinds.insert(id, type_kind);
fn_def_abis.insert(id, defn.abi.lower()?);
}
Item::TraitDefn(defn) => {
let type_kind = defn.lower_type_kind()?;
Expand Down Expand Up @@ -374,6 +378,7 @@ impl LowerProgram for Program {
adt_kinds: &adt_kinds,
fn_def_ids: &fn_def_ids,
fn_def_kinds: &fn_def_kinds,
fn_def_abis: &fn_def_abis,
trait_ids: &trait_ids,
trait_kinds: &trait_kinds,
opaque_ty_ids: &opaque_ty_ids,
Expand Down Expand Up @@ -1045,11 +1050,26 @@ impl LowerFnDefn for FnDefn {

Ok(rust_ir::FnDefDatum {
id: fn_def_id,
abi: self.abi.lower()?,
binders,
})
}
}

trait LowerFnAbi {
fn lower(&self) -> LowerResult<ChalkFnAbi>;
}

impl LowerFnAbi for FnAbi {
fn lower(&self) -> LowerResult<ChalkFnAbi> {
match self.0.as_ref() {
"Rust" => Ok(ChalkFnAbi::Rust),
"C" => Ok(ChalkFnAbi::C),
_ => Err(RustIrError::InvalidExternAbi(self.0.clone())),
}
}
}

trait LowerTraitRef {
fn lower(&self, env: &Env) -> LowerResult<chalk_ir::TraitRef<ChalkIr>>;
}
Expand Down Expand Up @@ -1394,8 +1414,8 @@ impl LowerTy for Ty {
.intern(interner)),

Ty::ForAll {
ref lifetime_names,
ref types,
lifetime_names,
types,
} => {
let quantified_env = env.introduce(lifetime_names.iter().map(|id| {
chalk_ir::WithKind::new(chalk_ir::VariableKind::Lifetime, id.str.clone())
Expand Down Expand Up @@ -1733,6 +1753,11 @@ impl LowerGoal<LoweredProgram> for Goal {
((datum.trait_id, datum.name.clone()), lookup)
})
.collect();
let fn_def_abis: BTreeMap<_, _> = program
.fn_def_data
.iter()
.map(|fn_def_data| (*fn_def_data.0, fn_def_data.1.abi))
.collect();

let env = Env {
adt_ids: &program.adt_ids,
Expand All @@ -1741,6 +1766,7 @@ impl LowerGoal<LoweredProgram> for Goal {
opaque_ty_ids: &program.opaque_ty_ids,
adt_kinds: &program.adt_kinds,
fn_def_kinds: &program.fn_def_kinds,
fn_def_abis: &fn_def_abis,
trait_kinds: &program.trait_kinds,
opaque_ty_kinds: &program.opaque_ty_kinds,
associated_ty_lookups: &associated_ty_lookups,
Expand Down
3 changes: 3 additions & 0 deletions chalk-ir/src/interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash {

type Identifier: Debug + Clone + Eq + Hash;

type FnAbi: Debug + Copy + Eq + Hash;

/// Prints the debug representation of a type-kind-id. To get good
/// results, this requires inspecting TLS, and is difficult to
/// code without reference to a specific interner (and hence
Expand Down Expand Up @@ -671,6 +673,7 @@ pub trait TargetInterner<I: Interner>: Interner {
fn transfer_canonical_var_kinds(
variable_kinds: I::InternedCanonicalVarKinds,
) -> Self::InternedCanonicalVarKinds;

fn transfer_const(
&self,
const_evaluated: &I::InternedConcreteConst,
Expand Down
10 changes: 10 additions & 0 deletions chalk-parse/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ pub struct FnDefn {
pub where_clauses: Vec<QuantifiedWhereClause>,
pub argument_types: Vec<Ty>,
pub return_type: Ty,
pub abi: FnAbi,
}

#[derive(Clone, Eq, PartialEq, Debug)]
pub struct FnAbi(pub Atom);

impl Default for FnAbi {
fn default() -> Self {
FnAbi(Atom::from("Rust"))
}
}

#[derive(Clone, PartialEq, Eq, Debug)]
Expand Down
18 changes: 8 additions & 10 deletions chalk-parse/src/parser.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -80,17 +80,20 @@ FnReturn: Ty = {
};

FnDefn: FnDefn = {
"fn" <n:Id> <p:Angle<VariableKind>>"(" <args:FnArgs> ")"
<abi:FnAbi?> "fn" <n:Id> <p:Angle<VariableKind>>"(" <args:FnArgs> ")"
<ret_ty:FnReturn?> <w:QuantifiedWhereClauses> ";" => FnDefn
{
name: n,
variable_kinds: p,
where_clauses: w,
argument_types: args,
return_type: ret_ty.unwrap_or_else(|| Ty::Tuple { types: Vec::new() }),
abi: abi.unwrap_or_default(),
}
};

FnAbi: FnAbi = "extern" "\"" <id:Id> "\"" => FnAbi(id.str);

FnArg: Ty = {
Id ":" <arg_ty: Ty> => arg_ty
};
Expand Down Expand Up @@ -227,8 +230,8 @@ pub Ty: Ty = {
};

TyWithoutId: Ty = {
"for" "<" <l:Comma<LifetimeId>> ">" "fn" "(" <types:Comma<Ty>> ")" <ret_ty:FnReturn?> => Ty::ForAll {
lifetime_names: l,
<l:ForLifetimes?> "fn" "(" <types:Comma<Ty>> ")" <ret_ty:FnReturn?> => Ty::ForAll {
lifetime_names: l.unwrap_or_default(),
types: types
.into_iter()
.chain(std::iter::once(ret_ty.unwrap_or_else(|| Ty::Tuple { types: Vec::new() })))
Expand All @@ -237,13 +240,6 @@ TyWithoutId: Ty = {
<ScalarType> => Ty::Scalar { ty: <> },
"str" => Ty::Str,
"!" => Ty::Never,
"fn" "(" <types:Comma<Ty>> ")" <ret_ty:FnReturn?> => Ty::ForAll {
lifetime_names: vec![],
types: types
.into_iter()
.chain(std::iter::once(ret_ty.unwrap_or_else(|| Ty::Tuple { types: Vec::new() })))
.map(Box::new).collect()
},
"dyn" <b:Plus<QuantifiedInlineBound>> "+" <l:Lifetime> => Ty::Dyn {
bounds: b,
lifetime: l,
Expand All @@ -258,6 +254,8 @@ TyWithoutId: Ty = {
"[" <t:Ty> ";" <len:Const> "]" => Ty::Array { ty: Box::new(t), len },
};

ForLifetimes: Vec<Identifier> = "for" "<" <Comma<LifetimeId>> ">" => <>;

ScalarType: ScalarType = {
"u8" => ScalarType::Uint(UintTy::U8),
"u16" => ScalarType::Uint(UintTy::U16),
Expand Down
1 change: 1 addition & 0 deletions chalk-solve/src/rust_ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ pub struct AdtFlags {
/// a specific function definition.
pub struct FnDefDatum<I: Interner> {
pub id: FnDefId<I>,
pub abi: I::FnAbi,
pub binders: Binders<FnDefDatumBound<I>>,
}

Expand Down
21 changes: 21 additions & 0 deletions tests/lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -696,3 +696,24 @@ fn phantom_data() {
}
}
}

#[test]
fn extern_functions() {
lowering_success! {
program {
extern "C" fn foo();

extern "Rust" fn bar();
}
}

lowering_error! {
program {
extern "Foo" fn foo();
}

error_msg {
"invalid extern ABI `Foo`"
}
}
}

0 comments on commit bf33634

Please sign in to comment.