Skip to content

Add the str type #441

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions book/src/clauses/well_known_traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 | ✅ | ✅ | ✅ | ⚬ | ⚬ | ⚬ | ⚬ | ⚬ | ❌ |
Expand Down
7 changes: 7 additions & 0 deletions chalk-integration/src/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<chalk_ir::Ty<ChalkIr>>;
}

Expand Down Expand Up @@ -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)),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions chalk-ir/src/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ impl<I: Interner> Debug for TypeName<I> {
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}}"),
Expand Down
7 changes: 5 additions & 2 deletions chalk-ir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ pub enum TypeName<I: Interner> {
/// a placeholder for opaque types like `impl Trait`
OpaqueType(OpaqueTyId<I>),

/// 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,
Expand Down Expand Up @@ -966,7 +969,7 @@ pub enum WhereClause<I: Interner> {

#[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)]
pub enum WellFormed<I: Interner> {
/// 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
Expand All @@ -981,7 +984,7 @@ pub enum WellFormed<I: Interner> {
/// ```
Trait(TraitRef<I>),

/// 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
Expand Down
1 change: 1 addition & 0 deletions chalk-parse/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ pub enum Ty {
lifetime: Lifetime,
ty: Box<Ty>,
},
Str,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
Expand Down
1 change: 1 addition & 0 deletions chalk-parse/src/parser.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ pub Ty: Ty = {

TyWithoutFor: Ty = {
<ScalarType> => Ty::Scalar { ty: <> },
"str" => Ty::Str,
<n:Id> => Ty::Id { name: n},
"fn" "(" <t:Ty> ")" => Ty::ForAll {
lifetime_names: vec![],
Expand Down
2 changes: 2 additions & 0 deletions chalk-solve/src/clauses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ fn match_ty<I: Interner>(
})
}

/// Lower a Rust IR application type to logic
fn match_type_name<I: Interner>(
builder: &mut ClauseBuilder<'_, I>,
interner: &I,
Expand All @@ -408,6 +409,7 @@ fn match_type_name<I: Interner>(
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)))
}
Expand Down
2 changes: 1 addition & 1 deletion tests/lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]|_)*\\\"#\"] }"
}
}
}
19 changes: 9 additions & 10 deletions tests/test/coherence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,31 +257,30 @@ 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<T> Bar for T where T: Sized { }
} error_msg {
"overlapping impls of trait `Bar`"
}
}

// 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<T> Bar for T where T: Sized { }
}
}
Expand Down
1 change: 1 addition & 0 deletions tests/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ mod projection;
mod refs;
mod scalars;
mod slices;
mod string;
mod tuples;
mod unify;
mod wf_goals;
54 changes: 54 additions & 0 deletions tests/test/string.rs
Original file line number Diff line number Diff line change
@@ -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" }
}
}
1 change: 0 additions & 1 deletion tests/test/wf_lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down