diff --git a/src/doc/reference.md b/src/doc/reference.md index 9851e1c28fbf0..d6a4375536b34 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2382,6 +2382,8 @@ The currently implemented features of the reference compiler are: semantics are likely to change, so this macro usage must be opted into. +* `associated_types` - Allows type aliases in traits. Experimental. + * `concat_idents` - Allows use of the `concat_idents` macro, which is in many ways insufficient for concatenating identifiers, and may be removed entirely for something more wholesome. @@ -2389,6 +2391,9 @@ The currently implemented features of the reference compiler are: * `default_type_params` - Allows use of default type parameters. The future of this feature is uncertain. +* `equality_constraints` - Allows the use of `=` in where clauses. This + allows a user to demand that two type's normal forms are equal. + * `intrinsics` - Allows use of the "rust-intrinsics" ABI. Compiler intrinsics are inherently unstable and no promise about them is made. @@ -2465,8 +2470,6 @@ The currently implemented features of the reference compiler are: Such items should not be allowed by the compiler to exist, so if you need this there probably is a compiler bug. -* `associated_types` - Allows type aliases in traits. Experimental. - If a feature is promoted to a language feature, then all existing programs will start to receive compilation warnings about #[feature] directives which enabled the new feature (because the directive is no longer necessary). However, if a diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 5e27023e026fb..1ffacb4e9d477 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -211,12 +211,11 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { self.visit_lifetime_ref(bound); } } - &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ id, - ref path, - ref ty, + &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ ref ty_left, + ref ty_right, .. }) => { - self.visit_path(path, id); - self.visit_ty(&**ty); + self.visit_ty(&**ty_left); + self.visit_ty(&**ty_right); } } } @@ -555,7 +554,12 @@ fn early_bound_lifetime_names(generics: &ast::Generics) -> Vec { collector.visit_lifetime_ref(bound); } } - &ast::WherePredicate::EqPredicate(_) => unimplemented!() + &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref ty_left, + ref ty_right, + ..}) => { + collector.visit_ty(&**ty_left); + collector.visit_ty(&**ty_right); + } } } } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index aa9b6c479bb78..dd96957f5aeca 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1453,7 +1453,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { } &ast::WherePredicate::RegionPredicate(_) => {} &ast::WherePredicate::EqPredicate(ref eq_pred) => { - self.visit_ty(&*eq_pred.ty); + self.visit_ty(&*eq_pred.ty_left); + self.visit_ty(&*eq_pred.ty_right); } } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a261599a70656..54c7fdcb2ae09 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3205,17 +3205,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } &ast::WherePredicate::RegionPredicate(_) => {} &ast::WherePredicate::EqPredicate(ref eq_pred) => { - match self.resolve_path(eq_pred.id, &eq_pred.path, TypeNS, true) { - Some((def @ DefTyParam(..), last_private)) => { - self.record_def(eq_pred.id, (def, last_private)); - } - _ => { - self.resolve_error(eq_pred.path.span, - "undeclared associated type"); - } - } - - self.resolve_type(&*eq_pred.ty); + self.resolve_type(&*eq_pred.ty_left); + self.resolve_type(&*eq_pred.ty_right); } } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index ce26658cf4b93..f582664a6cbf0 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1293,10 +1293,11 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, } &ast::WherePredicate::EqPredicate(ref eq_pred) => { - // FIXME(#20041) - ccx.tcx.sess.span_bug(eq_pred.span, - "Equality constraints are not yet \ - implemented (#20041)") + let ty_left = ast_ty_to_ty(ccx, &ExplicitRscope, &*eq_pred.ty_left); + let ty_right = ast_ty_to_ty(ccx, &ExplicitRscope, &*eq_pred.ty_right); + result.predicates.push(space, ty::Predicate::Equate( + ty::Binder(ty::EquatePredicate(ty_left, ty_right)) + )); } } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 7e1bf7a2230b8..36f407014f9fa 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -458,8 +458,8 @@ pub struct WhereRegionPredicate { pub struct WhereEqPredicate { pub id: NodeId, pub span: Span, - pub path: Path, - pub ty: P, + pub ty_left: P, + pub ty_right: P, } /// The set of MetaItems that define the compilation environment of the crate, diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 28573ef757b12..1c3cc22a69d24 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -458,8 +458,8 @@ impl<'a> TraitDef<'a> { ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { id: ast::DUMMY_NODE_ID, span: self.span, - path: we.path.clone(), - ty: we.ty.clone() + ty_right: we.ty_right.clone(), + ty_left: we.ty_left.clone() }) } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 12efd959918e1..6948813800507 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -122,7 +122,10 @@ static KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ ("staged_api", "1.0.0", Active), // Allows using items which are missing stability attributes - ("unmarked_api", "1.0.0", Active) + ("unmarked_api", "1.0.0", Active), + + // Enables equality constraints in where clauses. + ("equality_constraints", "1.0.0", Active) ]; enum Status { @@ -503,6 +506,20 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } visit::walk_fn(self, fn_kind, fn_decl, block, span); } + + fn visit_generics(&mut self, generics: &'v ast::Generics) { + for pred in generics.where_clause.predicates.iter() { + match pred { + &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{span, ..}) => { + self.gate_feature("equality_constraints", + span, "equality constraints are experimental") + }, + _ => {} + } + } + + visit::walk_generics(self, generics); + } } fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate, diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index b0ddb655882a8..fb660f7ed4b70 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -825,13 +825,13 @@ pub fn noop_fold_where_predicate( }) } ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{id, - path, - ty, + ty_left, + ty_right, span}) => { ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ id: fld.new_id(id), - path: fld.fold_path(path), - ty:fld.fold_ty(ty), + ty_left: fld.fold_ty(ty_left), + ty_right: fld.fold_ty(ty_right), span: fld.new_span(span) }) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 3107f47de7859..ee5043b7d598b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4245,21 +4245,20 @@ impl<'a> Parser<'a> { parsed_something = true; } else if self.eat(&token::Eq) { - // let ty = self.parse_ty(); + let ty = self.parse_ty(); let hi = self.span.hi; let span = mk_sp(lo, hi); - // generics.where_clause.predicates.push( - // ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { - // id: ast::DUMMY_NODE_ID, - // span: span, - // path: panic!("NYI"), //bounded_ty, - // ty: ty, - // })); - // parsed_something = true; - // // FIXME(#18433) - self.span_err(span, - "equality constraints are not yet supported \ - in where clauses (#20041)"); + generics.where_clause.predicates.push( + ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { + id: ast::DUMMY_NODE_ID, + span: span, + ty_left: bounded_ty, + ty_right: ty, + })); + parsed_something = true; + // self.span_err(span, + // "equality constraints are not yet supported \ + // in where clauses (#20041)"); } else { let last_span = self.last_span; self.span_err(last_span, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index c177cd1fafa55..8105d9876090e 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2516,11 +2516,13 @@ impl<'a> State<'a> { } } } - &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref path, ref ty, ..}) => { - try!(self.print_path(path, false)); + &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref ty_left, + ref ty_right, + ..}) => { + try!(self.print_type(&**ty_left)); try!(space(&mut self.s)); try!(self.word_space("=")); - try!(self.print_type(&**ty)); + try!(self.print_type(&**ty_right)); } } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 21cb62b0a0c11..1c7ce992120ca 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -597,12 +597,11 @@ pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics visitor.visit_lifetime_ref(bound); } } - &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{id, - ref path, - ref ty, + &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref ty_left, + ref ty_right, ..}) => { - visitor.visit_path(path, id); - visitor.visit_ty(&**ty); + visitor.visit_ty(&**ty_left); + visitor.visit_ty(&**ty_right); } } } diff --git a/src/test/compile-fail/where-clause-equality-constraint.rs b/src/test/compile-fail/where-clause-equality-constraint.rs new file mode 100644 index 0000000000000..58b76f71e910c --- /dev/null +++ b/src/test/compile-fail/where-clause-equality-constraint.rs @@ -0,0 +1,30 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(equality_constraints)] + +trait Foo where A = isize { + type Inner; + + fn foo_bar(&self) where Self::Inner = String {} +} + +// Failure to meet equality constraint on a trait definiton. +impl Foo for () { + //~^ the requirement `collections::string::String == isize` is not satisfied + type Inner = bool; + + fn foo_bar(&self) {} +} + +fn main() { + // Failure to meet associated type constraint on a method + ().foo_bar() +} diff --git a/src/test/run-pass/where-clause-equality-constraint.rs b/src/test/run-pass/where-clause-equality-constraint.rs new file mode 100644 index 0000000000000..b802d2ab8c0d2 --- /dev/null +++ b/src/test/run-pass/where-clause-equality-constraint.rs @@ -0,0 +1,27 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(equality_constraints)] + +trait Foo where A = isize { + type Inner; + + fn foo_bar(&self) where Self::Inner = String {} +} + +impl Foo for () { + type Inner = String; + + fn foo_bar(&self) {} +} + +fn main() { + ().foo_bar() +}