diff --git a/book/src/clauses/well_known_traits.md b/book/src/clauses/well_known_traits.md index 51eb6808c6c..f7e1ebf9311 100644 --- a/book/src/clauses/well_known_traits.md +++ b/book/src/clauses/well_known_traits.md @@ -33,6 +33,7 @@ Some common examples of auto traits are `Send` and `Sync`. | tuple types | ✅ | ✅ | ✅ | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ❌ | | structs | ⚬ | ⚬ | ✅ | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ✅ | | scalar types | 📚 | 📚 | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ❌ | +| str | 📚 | 📚 | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ❌ | | trait objects | ⚬ | ⚬ | ⚬ | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | | functions ptrs | ✅ | ✅ | ✅ | ⚬ | ⚬ | ❌ | ⚬ | ⚬ | ❌ | | raw ptrs | ✅ | ✅ | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ❌ | diff --git a/chalk-integration/src/lowering.rs b/chalk-integration/src/lowering.rs index 0e69e88a46f..83509adb03f 100644 --- a/chalk-integration/src/lowering.rs +++ b/chalk-integration/src/lowering.rs @@ -1085,6 +1085,7 @@ impl LowerProjectionTy for ProjectionTy { } trait LowerTy { + /// Lower from the AST to Chalk's Rust IR fn lower(&self, env: &Env) -> LowerResult>; } @@ -1257,6 +1258,12 @@ impl LowerTy for Ty { ), }) .intern(interner)), + + Ty::Str => Ok(chalk_ir::TyData::Apply(chalk_ir::ApplicationTy { + name: chalk_ir::TypeName::Str, + substitution: chalk_ir::Substitution::empty(interner), + }) + .intern(interner)), } } } diff --git a/chalk-ir/src/debug.rs b/chalk-ir/src/debug.rs index cb80978131d..9133c965cb7 100644 --- a/chalk-ir/src/debug.rs +++ b/chalk-ir/src/debug.rs @@ -142,6 +142,7 @@ impl Debug for TypeName { TypeName::Struct(id) => write!(fmt, "{:?}", id), TypeName::AssociatedType(assoc_ty) => write!(fmt, "{:?}", assoc_ty), TypeName::Scalar(scalar) => write!(fmt, "{:?}", scalar), + TypeName::Str => write!(fmt, "Str"), TypeName::Tuple(arity) => write!(fmt, "{:?}", arity), TypeName::OpaqueType(opaque_ty) => write!(fmt, "!{:?}", opaque_ty), TypeName::Slice => write!(fmt, "{{slice}}"), diff --git a/chalk-ir/src/lib.rs b/chalk-ir/src/lib.rs index 5319731e5ae..c029c753482 100644 --- a/chalk-ir/src/lib.rs +++ b/chalk-ir/src/lib.rs @@ -168,6 +168,9 @@ pub enum TypeName { /// a placeholder for opaque types like `impl Trait` OpaqueType(OpaqueTyId), + /// the string primitive type + Str, + /// 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, @@ -966,7 +969,7 @@ pub enum WhereClause { #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub enum WellFormed { - /// A predicate which is true is some trait ref is well-formed. + /// A predicate which is true when some trait ref is well-formed. /// For example, given the following trait definitions: /// /// ```notrust @@ -981,7 +984,7 @@ pub enum WellFormed { /// ``` Trait(TraitRef), - /// A predicate which is true is some type is well-formed. + /// A predicate which is true when some type is well-formed. /// For example, given the following type definition: /// /// ```notrust diff --git a/chalk-parse/src/ast.rs b/chalk-parse/src/ast.rs index eaeb02b301c..9f4d969ecc5 100644 --- a/chalk-parse/src/ast.rs +++ b/chalk-parse/src/ast.rs @@ -206,6 +206,7 @@ pub enum Ty { lifetime: Lifetime, ty: Box, }, + Str, } #[derive(Copy, Clone, PartialEq, Eq, Debug)] diff --git a/chalk-parse/src/parser.lalrpop b/chalk-parse/src/parser.lalrpop index cec56342053..ca7c3909229 100644 --- a/chalk-parse/src/parser.lalrpop +++ b/chalk-parse/src/parser.lalrpop @@ -196,6 +196,7 @@ pub Ty: Ty = { TyWithoutFor: Ty = { => Ty::Scalar { ty: <> }, + "str" => Ty::Str, => Ty::Id { name: n}, "fn" "(" ")" => Ty::ForAll { lifetime_names: vec![], diff --git a/chalk-solve/src/clauses.rs b/chalk-solve/src/clauses.rs index 6a9316badae..445674ae94d 100644 --- a/chalk-solve/src/clauses.rs +++ b/chalk-solve/src/clauses.rs @@ -389,6 +389,7 @@ fn match_ty( }) } +/// Lower a Rust IR application type to logic fn match_type_name( builder: &mut ClauseBuilder<'_, I>, interner: &I, @@ -408,6 +409,7 @@ fn match_type_name( TypeName::Scalar(_) => { builder.push_fact(WellFormed::Ty(application.clone().intern(interner))) } + TypeName::Str => builder.push_fact(WellFormed::Ty(application.clone().intern(interner))), TypeName::Tuple(_) => { builder.push_fact(WellFormed::Ty(application.clone().intern(interner))) } diff --git a/tests/lowering/mod.rs b/tests/lowering/mod.rs index 932186ee1dc..f31e2d53780 100644 --- a/tests/lowering/mod.rs +++ b/tests/lowering/mod.rs @@ -555,7 +555,7 @@ fn slices() { } error_msg { - "parse error: UnrecognizedToken { token: (29, Token(31, \"]\"), 30), expected: [\"\\\"&\\\"\", \"\\\"(\\\"\", \"\\\"*\\\"\", \"\\\"<\\\"\", \"\\\"[\\\"\", \"\\\"bool\\\"\", \"\\\"char\\\"\", \"\\\"dyn\\\"\", \"\\\"f32\\\"\", \"\\\"f64\\\"\", \"\\\"fn\\\"\", \"\\\"for\\\"\", \"\\\"i128\\\"\", \"\\\"i16\\\"\", \"\\\"i32\\\"\", \"\\\"i64\\\"\", \"\\\"i8\\\"\", \"\\\"isize\\\"\", \"\\\"u128\\\"\", \"\\\"u16\\\"\", \"\\\"u32\\\"\", \"\\\"u64\\\"\", \"\\\"u8\\\"\", \"\\\"usize\\\"\", \"r#\\\"([A-Za-z]|_)([A-Za-z0-9]|_)*\\\"#\"] }" + "parse error: UnrecognizedToken { token: (29, Token(31, \"]\"), 30), expected: [\"\\\"&\\\"\", \"\\\"(\\\"\", \"\\\"*\\\"\", \"\\\"<\\\"\", \"\\\"[\\\"\", \"\\\"bool\\\"\", \"\\\"char\\\"\", \"\\\"dyn\\\"\", \"\\\"f32\\\"\", \"\\\"f64\\\"\", \"\\\"fn\\\"\", \"\\\"for\\\"\", \"\\\"i128\\\"\", \"\\\"i16\\\"\", \"\\\"i32\\\"\", \"\\\"i64\\\"\", \"\\\"i8\\\"\", \"\\\"isize\\\"\", \"\\\"str\\\"\", \"\\\"u128\\\"\", \"\\\"u16\\\"\", \"\\\"u32\\\"\", \"\\\"u64\\\"\", \"\\\"u8\\\"\", \"\\\"usize\\\"\", \"r#\\\"([A-Za-z]|_)([A-Za-z0-9]|_)*\\\"#\"] }" } } } diff --git a/tests/test/coherence.rs b/tests/test/coherence.rs index d2547d6236b..bbe8044b0a8 100644 --- a/tests/test/coherence.rs +++ b/tests/test/coherence.rs @@ -257,16 +257,15 @@ fn downstream_impl_of_fundamental_43355() { #[test] fn fundamental_traits() { - // We want to enable negative reasoning about some traits. For example, consider the str type. - // We know that str is never going to be Sized and we have made a decision to allow people to - // depend on that. The following two impls are rejected as overlapping despite the fact that we - // know that str will never be Sized. + // We want to enable negative reasoning about some traits. For example, assume we have some + // "Foo" type which we know is never going to be Sized (ex. str). The following two impls are + // rejected as overlapping despite the fact that we know that Foo will never be Sized. lowering_error! { program { #[upstream] trait Sized { } - #[upstream] struct str { } + #[upstream] struct Foo { } trait Bar { } - impl Bar for str { } + impl Bar for Foo { } impl Bar for T where T: Sized { } } error_msg { "overlapping impls of trait `Bar`" @@ -274,14 +273,14 @@ fn fundamental_traits() { } // If we make Sized fundamental, we're telling the Rust compiler that it can reason negatively - // about it. That means that `not { str: Sized }` is provable. With that change, these two - // impls are now valid. + // about it. That means that `not { Foo: Sized }` is provable. With that change, these two impls + // are now valid. lowering_success! { program { #[upstream] #[fundamental] trait Sized { } - #[upstream] struct str { } + #[upstream] struct Foo { } trait Bar { } - impl Bar for str { } + impl Bar for Foo { } impl Bar for T where T: Sized { } } } diff --git a/tests/test/mod.rs b/tests/test/mod.rs index b7a6da16ab9..c5f184658fd 100644 --- a/tests/test/mod.rs +++ b/tests/test/mod.rs @@ -318,6 +318,7 @@ mod projection; mod refs; mod scalars; mod slices; +mod string; mod tuples; mod unify; mod wf_goals; diff --git a/tests/test/string.rs b/tests/test/string.rs new file mode 100644 index 00000000000..bc5aa9fcca2 --- /dev/null +++ b/tests/test/string.rs @@ -0,0 +1,54 @@ +use super::*; + +#[test] +fn str_trait_impl() { + test! { + program { + trait Foo {} + impl Foo for str {} + } + + goal { str: Foo } yields { "Unique" } + } +} + +#[test] +fn str_is_well_formed() { + test! { + program {} + goal { WellFormed(str) } yields { "Unique" } + } +} + +#[test] +fn str_is_not_sized() { + test! { + program { + #[lang(sized)] trait Sized {} + } + + goal { not { str: Sized } } yields { "Unique" } + } +} + +#[test] +fn str_is_not_copy() { + test! { + program { + #[lang(copy)] trait Copy {} + } + + goal { not { str: Copy } } yields { "Unique" } + } +} + +#[test] +fn str_is_not_clone() { + test! { + program { + #[lang(clone)] trait Clone {} + } + + goal { not { str: Clone } } yields { "Unique" } + } +} diff --git a/tests/test/wf_lowering.rs b/tests/test/wf_lowering.rs index 36fc24de986..e2dd6e3d1b5 100644 --- a/tests/test/wf_lowering.rs +++ b/tests/test/wf_lowering.rs @@ -576,7 +576,6 @@ fn assoc_type_recursive_bound() { } struct Number { } - struct str { } // not sized impl Foo for Number { // Well-formedness checks require that the following