Skip to content
26 changes: 24 additions & 2 deletions chalk-integration/src/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ use crate::interner::{ChalkFnAbi, ChalkIr};
use chalk_ir::cast::{Cast, Caster};
use chalk_ir::interner::{HasInterner, Interner};
use chalk_ir::{
self, AdtId, AssocTypeId, BoundVar, ClausePriority, ClosureId, DebruijnIndex, FnDefId, ImplId,
OpaqueTyId, QuantifiedWhereClauses, Substitution, ToGenericArg, TraitId, TyKind, VariableKinds,
self, AdtId, AssocTypeId, BoundVar, ClausePriority, ClosureId, DebruijnIndex, FnDefId,
ForeignDefId, ImplId, OpaqueTyId, QuantifiedWhereClauses, Substitution, ToGenericArg, TraitId,
TyKind, VariableKinds,
};
use chalk_parse::ast::*;
use chalk_solve::rust_ir::{
Expand Down Expand Up @@ -33,6 +34,7 @@ type OpaqueTyKinds = BTreeMap<chalk_ir::OpaqueTyId<ChalkIr>, TypeKind>;
type AssociatedTyLookups = BTreeMap<(chalk_ir::TraitId<ChalkIr>, Ident), AssociatedTyLookup>;
type AssociatedTyValueIds =
BTreeMap<(chalk_ir::ImplId<ChalkIr>, Ident), AssociatedTyValueId<ChalkIr>>;
type ForeignIds = BTreeMap<Ident, chalk_ir::ForeignDefId<ChalkIr>>;

type ParameterMap = BTreeMap<Ident, chalk_ir::WithKind<ChalkIr, BoundVar>>;

Expand All @@ -53,6 +55,7 @@ struct Env<'k> {
opaque_ty_kinds: &'k OpaqueTyKinds,
associated_ty_lookups: &'k AssociatedTyLookups,
auto_traits: &'k AutoTraits,
foreign_ty_ids: &'k ForeignIds,
/// GenericArg identifiers are used as keys, therefore
/// all identifiers in an environment must be unique (no shadowing).
parameter_map: ParameterMap,
Expand Down Expand Up @@ -177,6 +180,16 @@ impl<'k> Env<'k> {
.cast(interner),
);
}

if let Some(id) = self.foreign_ty_ids.get(&name.str) {
return Ok(chalk_ir::TyData::Apply(chalk_ir::ApplicationTy {
name: chalk_ir::TypeName::Foreign(*id),
substitution: chalk_ir::Substitution::empty(interner),
})
.intern(interner)
.cast(interner));
}

if let Some(_) = self.trait_ids.get(&name.str) {
return Err(RustIrError::NotStruct(name.clone()));
}
Expand Down Expand Up @@ -408,6 +421,7 @@ impl LowerProgram for Program {
}
Item::Impl(_) => continue,
Item::Clause(_) => continue,
Item::Foreign(_) => continue,
};
}

Expand All @@ -425,6 +439,8 @@ impl LowerProgram for Program {
let mut opaque_ty_data = BTreeMap::new();
let mut hidden_opaque_types = BTreeMap::new();
let mut custom_clauses = Vec::new();
let mut foreign_ty_ids = BTreeMap::new();

for (item, &raw_id) in self.items.iter().zip(&raw_ids) {
let empty_env = Env {
adt_ids: &adt_ids,
Expand All @@ -441,6 +457,7 @@ impl LowerProgram for Program {
associated_ty_lookups: &associated_ty_lookups,
parameter_map: BTreeMap::new(),
auto_traits: &auto_traits,
foreign_ty_ids: &foreign_ty_ids,
};

match *item {
Expand Down Expand Up @@ -638,6 +655,9 @@ impl LowerProgram for Program {
);
}
}
Item::Foreign(ForeignDefn(ref ident)) => {
foreign_ty_ids.insert(ident.str.clone(), ForeignDefId(raw_id));
}
}
}

Expand Down Expand Up @@ -667,6 +687,7 @@ impl LowerProgram for Program {
hidden_opaque_types,
custom_clauses,
object_safe_traits,
foreign_ty_ids,
};

Ok(program)
Expand Down Expand Up @@ -2016,6 +2037,7 @@ impl LowerGoal<LoweredProgram> for Goal {
trait_kinds: &program.trait_kinds,
opaque_ty_kinds: &program.opaque_ty_kinds,
associated_ty_lookups: &associated_ty_lookups,
foreign_ty_ids: &program.foreign_ty_ids,
parameter_map: BTreeMap::new(),
auto_traits: &auto_traits,
};
Expand Down
7 changes: 5 additions & 2 deletions chalk-integration/src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use chalk_ir::could_match::CouldMatch;
use chalk_ir::debug::Angle;
use chalk_ir::{
debug::SeparatorTraitRef, AdtId, AliasTy, ApplicationTy, AssocTypeId, Binders,
CanonicalVarKinds, ClosureId, FnDefId, GenericArg, Goal, Goals, ImplId, Lifetime, OpaqueTy,
OpaqueTyId, ProgramClause, ProgramClauseImplication, ProgramClauses, ProjectionTy,
CanonicalVarKinds, ClosureId, FnDefId, ForeignDefId, GenericArg, Goal, Goals, ImplId, Lifetime,
OpaqueTy, OpaqueTyId, ProgramClause, ProgramClauseImplication, ProgramClauses, ProjectionTy,
Substitution, TraitId, Ty,
};
use chalk_solve::rust_ir::{
Expand Down Expand Up @@ -89,6 +89,9 @@ pub struct Program {

/// Store the traits marked with `#[object_safe]`
pub object_safe_traits: HashSet<TraitId<ChalkIr>>,

/// For each foreign type `extern { type A; }`
pub foreign_ty_ids: BTreeMap<Identifier, ForeignDefId<ChalkIr>>,
}

impl Program {
Expand Down
8 changes: 8 additions & 0 deletions chalk-ir/src/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ impl<I: Interner> Debug for ClosureId<I> {
}
}

impl<I: Interner> Debug for ForeignDefId<I> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> std::fmt::Result {
I::debug_foreign_def_id(*self, fmt)
.unwrap_or_else(|| write!(fmt, "ForeignDefId({:?})", self.0))
}
}

impl<I: Interner> Debug for Ty<I> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> {
I::debug_ty(self, fmt).unwrap_or_else(|| write!(fmt, "{:?}", self.interned))
Expand Down Expand Up @@ -184,6 +191,7 @@ impl<I: Interner> Debug for TypeName<I> {
TypeName::Never => write!(fmt, "Never"),
TypeName::Array => write!(fmt, "{{array}}"),
TypeName::Closure(id) => write!(fmt, "{{closure:{:?}}}", id),
TypeName::Foreign(foreign_ty) => write!(fmt, "{:?}", foreign_ty),
TypeName::Error => write!(fmt, "{{error}}"),
}
}
Expand Down
1 change: 1 addition & 0 deletions chalk-ir/src/fold/boring_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ id_fold!(AssocTypeId);
id_fold!(OpaqueTyId);
id_fold!(FnDefId);
id_fold!(ClosureId);
id_fold!(ForeignDefId);

impl<I: Interner, TI: TargetInterner<I>> SuperFold<I, TI> for ProgramClauseData<I> {
fn super_fold_with<'i>(
Expand Down
11 changes: 11 additions & 0 deletions chalk-ir/src/interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::ClosureId;
use crate::Constraint;
use crate::Constraints;
use crate::FnDefId;
use crate::ForeignDefId;
use crate::GenericArg;
use crate::GenericArgData;
use crate::Goal;
Expand Down Expand Up @@ -245,6 +246,16 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash {
None
}

/// Prints the debug representation of a foreign-def-id.
/// Returns `None` to fallback to the default debug output.
#[allow(unused_variables)]
fn debug_foreign_def_id(
foreign_def_id: ForeignDefId<Self>,
fmt: &mut fmt::Formatter<'_>,
) -> Option<fmt::Result> {
None
}

/// Prints the debug representation of an alias.
/// Returns `None` to fallback to the default debug output.
#[allow(unused_variables)]
Expand Down
7 changes: 7 additions & 0 deletions chalk-ir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,9 @@ pub enum TypeName<I: Interner> {
/// A closure.
Closure(ClosureId<I>),

/// foreign types
Foreign(ForeignDefId<I>),

/// This can be used to represent an error, e.g. during name resolution of a type.
/// Chalk itself will not produce this, just pass it through when given.
Error,
Expand Down Expand Up @@ -363,6 +366,10 @@ pub struct FnDefId<I: Interner>(pub I::DefId);
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ClosureId<I: Interner>(pub I::DefId);

/// Id for foreign types.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ForeignDefId<I: Interner>(pub I::DefId);

impl_debugs!(ImplId, ClauseId);

/// A Rust type. The actual type data is stored in `TyData`.
Expand Down
8 changes: 5 additions & 3 deletions chalk-ir/src/visit/boring_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@

use crate::{
AdtId, AssocTypeId, ClausePriority, ClosureId, Constraints, DebruijnIndex, FloatTy, FnDefId,
GenericArg, Goals, ImplId, IntTy, Interner, Mutability, OpaqueTyId, PlaceholderIndex,
ProgramClause, ProgramClauses, QuantifiedWhereClauses, QuantifierKind, Safety, Scalar,
Substitution, SuperVisit, TraitId, UintTy, UniverseIndex, Visit, VisitResult, Visitor,
ForeignDefId, GenericArg, Goals, ImplId, IntTy, Interner, Mutability, OpaqueTyId,
PlaceholderIndex, ProgramClause, ProgramClauses, QuantifiedWhereClauses, QuantifierKind,
Safety, Scalar, Substitution, SuperVisit, TraitId, UintTy, UniverseIndex, Visit, VisitResult,
Visitor,
};
use std::{marker::PhantomData, sync::Arc};

Expand Down Expand Up @@ -239,6 +240,7 @@ id_visit!(OpaqueTyId);
id_visit!(AssocTypeId);
id_visit!(FnDefId);
id_visit!(ClosureId);
id_visit!(ForeignDefId);

impl<I: Interner> SuperVisit<I> for ProgramClause<I> {
fn super_visit_with<'i, R: VisitResult>(
Expand Down
4 changes: 4 additions & 0 deletions chalk-parse/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,12 @@ pub enum Item {
OpaqueTyDefn(OpaqueTyDefn),
Impl(Impl),
Clause(Clause),
Foreign(ForeignDefn),
}

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct ForeignDefn(pub Identifier);

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct AdtDefn {
pub name: Identifier,
Expand Down
5 changes: 5 additions & 0 deletions chalk-parse/src/parser.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ Item: Option<Item> = {
OpaqueTyDefn => Some(Item::OpaqueTyDefn(<>)),
Impl => Some(Item::Impl(<>)),
Clause => Some(Item::Clause(<>)),
ForeignType => Some(Item::Foreign(<>)),
};

ForeignType: ForeignDefn = {
"extern" "type" <id:Id> ";" => ForeignDefn(id),
};

Comment: () = r"//.*";
Expand Down
3 changes: 2 additions & 1 deletion chalk-solve/src/clauses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,8 @@ fn match_type_name<I: Interner>(
| TypeName::Ref(_)
| TypeName::Array
| TypeName::Never
| TypeName::Closure(_) => {
| TypeName::Closure(_)
| TypeName::Foreign(_) => {
builder.push_fact(WellFormed::Ty(application.clone().intern(interner)))
}
}
Expand Down
1 change: 1 addition & 0 deletions chalk-solve/src/clauses/builtin_traits/copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ pub fn add_copy_program_clauses<I: Interner>(
| TypeName::AssociatedType(_)
| TypeName::Slice
| TypeName::OpaqueType(_)
| TypeName::Foreign(_)
| TypeName::Error => {}
},

Expand Down
1 change: 1 addition & 0 deletions chalk-solve/src/clauses/builtin_traits/sized.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ pub fn add_sized_program_clauses<I: Interner>(
| TypeName::Slice
| TypeName::OpaqueType(_)
| TypeName::Str
| TypeName::Foreign(_)
| TypeName::Error => {}
},

Expand Down
1 change: 1 addition & 0 deletions chalk-solve/src/display/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ impl<I: Interner> RenderAsRust<I> for ApplicationTy<I> {
// FIXME: write out valid types for these variants
TypeName::FnDef(_) => write!(f, "<fn_def>")?,
TypeName::Closure(..) => write!(f, "<closure>")?,
TypeName::Foreign(_) => write!(f, "<foreign>")?,

TypeName::Array => write!(
f,
Expand Down
77 changes: 77 additions & 0 deletions tests/test/foreign_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//! Tests for foreign types

use super::*;

// foreign types don't implement any builtin traits
#[test]
fn foreign_ty_trait_impl() {
test! {
program {
extern type A;
trait Foo {}
impl Foo for A {}
}

goal { A: Foo } yields { "Unique" }
}
}

#[test]
fn foreign_ty_lowering() {
lowering_success! {
program {
extern type A;
}
}
}

// foreign types are always well-formed
#[test]
fn foreign_ty_is_well_formed() {
test! {
program {
extern type A;
}

goal { WellFormed(A) } yields { "Unique" }
}
}

// foreign types don't implement any builtin traits
#[test]
fn foreign_ty_is_not_sized() {
test! {
program {
#[lang(sized)] trait Sized {}
extern type A;
}

goal { not { A: Sized } } yields { "Unique" }
}
}

// foreign types don't implement any builtin traits
#[test]
fn foreign_ty_is_not_copy() {
test! {
program {
#[lang(copy)] trait Copy {}
extern type A;
}

goal { not { A: Copy } } yields { "Unique" }
}
}

// foreign types don't implement any builtin traits
#[test]
fn foreign_ty_is_not_clone() {
test! {
program {
#[lang(clone)] trait Clone {}
extern type A;
}

goal { not { A: Clone } } yields { "Unique" }
}
}
1 change: 1 addition & 0 deletions tests/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ mod constants;
mod cycle;
mod existential_types;
mod fn_def;
mod foreign_types;
mod implied_bounds;
mod impls;
mod misc;
Expand Down