diff --git a/chalk-integration/src/lowering.rs b/chalk-integration/src/lowering.rs index e68ae55ea84..c803ee5ee97 100644 --- a/chalk-integration/src/lowering.rs +++ b/chalk-integration/src/lowering.rs @@ -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::{ @@ -33,6 +34,7 @@ type OpaqueTyKinds = BTreeMap, TypeKind>; type AssociatedTyLookups = BTreeMap<(chalk_ir::TraitId, Ident), AssociatedTyLookup>; type AssociatedTyValueIds = BTreeMap<(chalk_ir::ImplId, Ident), AssociatedTyValueId>; +type ForeignIds = BTreeMap>; type ParameterMap = BTreeMap>; @@ -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, @@ -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())); } @@ -408,6 +421,7 @@ impl LowerProgram for Program { } Item::Impl(_) => continue, Item::Clause(_) => continue, + Item::Foreign(_) => continue, }; } @@ -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, @@ -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 { @@ -638,6 +655,9 @@ impl LowerProgram for Program { ); } } + Item::Foreign(ForeignDefn(ref ident)) => { + foreign_ty_ids.insert(ident.str.clone(), ForeignDefId(raw_id)); + } } } @@ -667,6 +687,7 @@ impl LowerProgram for Program { hidden_opaque_types, custom_clauses, object_safe_traits, + foreign_ty_ids, }; Ok(program) @@ -2016,6 +2037,7 @@ impl LowerGoal 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, }; diff --git a/chalk-integration/src/program.rs b/chalk-integration/src/program.rs index fba68382395..de12b0875bc 100644 --- a/chalk-integration/src/program.rs +++ b/chalk-integration/src/program.rs @@ -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::{ @@ -89,6 +89,9 @@ pub struct Program { /// Store the traits marked with `#[object_safe]` pub object_safe_traits: HashSet>, + + /// For each foreign type `extern { type A; }` + pub foreign_ty_ids: BTreeMap>, } impl Program { diff --git a/chalk-ir/src/debug.rs b/chalk-ir/src/debug.rs index 7a7d3638c31..aaf2025b6c9 100644 --- a/chalk-ir/src/debug.rs +++ b/chalk-ir/src/debug.rs @@ -35,6 +35,13 @@ impl Debug for ClosureId { } } +impl Debug for ForeignDefId { + 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 Debug for Ty { fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { I::debug_ty(self, fmt).unwrap_or_else(|| write!(fmt, "{:?}", self.interned)) @@ -184,6 +191,7 @@ impl Debug for TypeName { 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}}"), } } diff --git a/chalk-ir/src/fold/boring_impls.rs b/chalk-ir/src/fold/boring_impls.rs index 9922315a398..9d6f835e1d6 100644 --- a/chalk-ir/src/fold/boring_impls.rs +++ b/chalk-ir/src/fold/boring_impls.rs @@ -303,6 +303,7 @@ id_fold!(AssocTypeId); id_fold!(OpaqueTyId); id_fold!(FnDefId); id_fold!(ClosureId); +id_fold!(ForeignDefId); impl> SuperFold for ProgramClauseData { fn super_fold_with<'i>( diff --git a/chalk-ir/src/interner.rs b/chalk-ir/src/interner.rs index c996059d97b..4accb4ac46a 100644 --- a/chalk-ir/src/interner.rs +++ b/chalk-ir/src/interner.rs @@ -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; @@ -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, + fmt: &mut fmt::Formatter<'_>, + ) -> Option { + None + } + /// Prints the debug representation of an alias. /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] diff --git a/chalk-ir/src/lib.rs b/chalk-ir/src/lib.rs index 6bdc09237b1..1963cd2421a 100644 --- a/chalk-ir/src/lib.rs +++ b/chalk-ir/src/lib.rs @@ -254,6 +254,9 @@ pub enum TypeName { /// A closure. Closure(ClosureId), + /// foreign types + Foreign(ForeignDefId), + /// 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, @@ -363,6 +366,10 @@ pub struct FnDefId(pub I::DefId); #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ClosureId(pub I::DefId); +/// Id for foreign types. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ForeignDefId(pub I::DefId); + impl_debugs!(ImplId, ClauseId); /// A Rust type. The actual type data is stored in `TyData`. diff --git a/chalk-ir/src/visit/boring_impls.rs b/chalk-ir/src/visit/boring_impls.rs index 242844fc40e..43e4cf16522 100644 --- a/chalk-ir/src/visit/boring_impls.rs +++ b/chalk-ir/src/visit/boring_impls.rs @@ -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}; @@ -239,6 +240,7 @@ id_visit!(OpaqueTyId); id_visit!(AssocTypeId); id_visit!(FnDefId); id_visit!(ClosureId); +id_visit!(ForeignDefId); impl SuperVisit for ProgramClause { fn super_visit_with<'i, R: VisitResult>( diff --git a/chalk-parse/src/ast.rs b/chalk-parse/src/ast.rs index 81f025c77a9..aee71042791 100644 --- a/chalk-parse/src/ast.rs +++ b/chalk-parse/src/ast.rs @@ -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, diff --git a/chalk-parse/src/parser.lalrpop b/chalk-parse/src/parser.lalrpop index 838a54f14ad..f24d98b11a3 100644 --- a/chalk-parse/src/parser.lalrpop +++ b/chalk-parse/src/parser.lalrpop @@ -20,6 +20,11 @@ Item: Option = { OpaqueTyDefn => Some(Item::OpaqueTyDefn(<>)), Impl => Some(Item::Impl(<>)), Clause => Some(Item::Clause(<>)), + ForeignType => Some(Item::Foreign(<>)), +}; + +ForeignType: ForeignDefn = { + "extern" "type" ";" => ForeignDefn(id), }; Comment: () = r"//.*"; diff --git a/chalk-solve/src/clauses.rs b/chalk-solve/src/clauses.rs index db54807664e..afb6a256bef 100644 --- a/chalk-solve/src/clauses.rs +++ b/chalk-solve/src/clauses.rs @@ -635,7 +635,8 @@ fn match_type_name( | TypeName::Ref(_) | TypeName::Array | TypeName::Never - | TypeName::Closure(_) => { + | TypeName::Closure(_) + | TypeName::Foreign(_) => { builder.push_fact(WellFormed::Ty(application.clone().intern(interner))) } } diff --git a/chalk-solve/src/clauses/builtin_traits/copy.rs b/chalk-solve/src/clauses/builtin_traits/copy.rs index 5fd9c1a17ac..d8528da8f2e 100644 --- a/chalk-solve/src/clauses/builtin_traits/copy.rs +++ b/chalk-solve/src/clauses/builtin_traits/copy.rs @@ -75,6 +75,7 @@ pub fn add_copy_program_clauses( | TypeName::AssociatedType(_) | TypeName::Slice | TypeName::OpaqueType(_) + | TypeName::Foreign(_) | TypeName::Error => {} }, diff --git a/chalk-solve/src/clauses/builtin_traits/sized.rs b/chalk-solve/src/clauses/builtin_traits/sized.rs index 786c705a29c..b256a4bf828 100644 --- a/chalk-solve/src/clauses/builtin_traits/sized.rs +++ b/chalk-solve/src/clauses/builtin_traits/sized.rs @@ -93,6 +93,7 @@ pub fn add_sized_program_clauses( | TypeName::Slice | TypeName::OpaqueType(_) | TypeName::Str + | TypeName::Foreign(_) | TypeName::Error => {} }, diff --git a/chalk-solve/src/display/ty.rs b/chalk-solve/src/display/ty.rs index 67927030964..8454cd15b67 100644 --- a/chalk-solve/src/display/ty.rs +++ b/chalk-solve/src/display/ty.rs @@ -217,6 +217,7 @@ impl RenderAsRust for ApplicationTy { // FIXME: write out valid types for these variants TypeName::FnDef(_) => write!(f, "")?, TypeName::Closure(..) => write!(f, "")?, + TypeName::Foreign(_) => write!(f, "")?, TypeName::Array => write!( f, diff --git a/tests/test/foreign_types.rs b/tests/test/foreign_types.rs new file mode 100644 index 00000000000..d525dbd0272 --- /dev/null +++ b/tests/test/foreign_types.rs @@ -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" } + } +} diff --git a/tests/test/mod.rs b/tests/test/mod.rs index b62ef509e5e..b25dd98fea0 100644 --- a/tests/test/mod.rs +++ b/tests/test/mod.rs @@ -329,6 +329,7 @@ mod constants; mod cycle; mod existential_types; mod fn_def; +mod foreign_types; mod implied_bounds; mod impls; mod misc;