From 85707398809f8b56afc471f228bd4d0137ce0a32 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 10 Mar 2015 23:12:55 -0500 Subject: [PATCH] allow inherent implementations on primitives --- src/librustc/middle/lang_items.rs | 18 +++ src/librustc/middle/ty.rs | 23 +++ src/librustc_typeck/check/method/probe.rs | 76 ++++++++++ src/librustc_typeck/coherence/orphan.rs | 137 ++++++++++++++++++ .../single-primitive-inherent-impl.rs | 24 +++ 5 files changed, 278 insertions(+) create mode 100644 src/test/compile-fail/single-primitive-inherent-impl.rs diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 3525d46a1f2..1ad4611dc9e 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -239,6 +239,24 @@ pub fn collect_language_items(krate: &ast::Crate, lets_do_this! { // Variant name, Name, Method name; + CharImplItem, "char", char_impl; + StrImplItem, "str", str_impl; + SliceImplItem, "slice", slice_impl; + ConstPtrImplItem, "const_ptr", const_ptr_impl; + MutPtrImplItem, "mut_ptr", mut_ptr_impl; + I8ImplItem, "i8", i8_impl; + I16ImplItem, "i16", i16_impl; + I32ImplItem, "i32", i32_impl; + I64ImplItem, "i64", i64_impl; + IsizeImplItem, "isize", isize_impl; + U8ImplItem, "u8", u8_impl; + U16ImplItem, "u16", u16_impl; + U32ImplItem, "u32", u32_impl; + U64ImplItem, "u64", u64_impl; + UsizeImplItem, "usize", usize_impl; + F32ImplItem, "f32", f32_impl; + F64ImplItem, "f64", f64_impl; + SendTraitLangItem, "send", send_trait; SizedTraitLangItem, "sized", sized_trait; CopyTraitLangItem, "copy", copy_trait; diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 8705e56b094..c3e1879fca8 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -788,6 +788,9 @@ pub struct ctxt<'tcx> { /// is used for lazy resolution of traits. pub populated_external_traits: RefCell, + /// The set of external primitive inherent implementations that have been read. + pub populated_external_primitive_impls: RefCell, + /// Borrows pub upvar_capture_map: RefCell, @@ -2599,6 +2602,7 @@ pub fn mk_ctxt<'tcx>(s: Session, used_mut_nodes: RefCell::new(NodeSet()), populated_external_types: RefCell::new(DefIdSet()), populated_external_traits: RefCell::new(DefIdSet()), + populated_external_primitive_impls: RefCell::new(DefIdSet()), upvar_capture_map: RefCell::new(FnvHashMap()), extern_const_statics: RefCell::new(DefIdMap()), extern_const_variants: RefCell::new(DefIdMap()), @@ -5988,6 +5992,25 @@ pub fn record_trait_implementation(tcx: &ctxt, tcx.trait_impls.borrow_mut().insert(trait_def_id, Rc::new(RefCell::new(vec!(impl_def_id)))); } +/// Load primitive inherent implementations if necessary +pub fn populate_implementations_for_primitive_if_necessary(tcx: &ctxt, lang_def_id: ast::DefId) { + if lang_def_id.krate == LOCAL_CRATE { + return + } + if tcx.populated_external_primitive_impls.borrow().contains(&lang_def_id) { + return + } + + debug!("populate_implementations_for_primitive_if_necessary: searching for {:?}", lang_def_id); + + let impl_items = csearch::get_impl_items(&tcx.sess.cstore, lang_def_id); + + // Store the implementation info. + tcx.impl_items.borrow_mut().insert(lang_def_id, impl_items); + + tcx.populated_external_primitive_impls.borrow_mut().insert(lang_def_id); +} + /// Populates the type context with all the implementations for the given type /// if necessary. pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 718804d317f..1f7cc3bb647 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -289,11 +289,87 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { ty::ty_param(p) => { self.assemble_inherent_candidates_from_param(self_ty, p); } + ty::ty_char => { + let lang_def_id = self.tcx().lang_items.char_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } + ty::ty_str => { + let lang_def_id = self.tcx().lang_items.str_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } + ty::ty_vec(_, None) => { + let lang_def_id = self.tcx().lang_items.slice_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } + ty::ty_ptr(ty::mt { ty: _, mutbl: ast::MutImmutable }) => { + let lang_def_id = self.tcx().lang_items.const_ptr_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } + ty::ty_ptr(ty::mt { ty: _, mutbl: ast::MutMutable }) => { + let lang_def_id = self.tcx().lang_items.mut_ptr_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } + ty::ty_int(ast::TyI8) => { + let lang_def_id = self.tcx().lang_items.i8_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } + ty::ty_int(ast::TyI16) => { + let lang_def_id = self.tcx().lang_items.i16_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } + ty::ty_int(ast::TyI32) => { + let lang_def_id = self.tcx().lang_items.i32_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } + ty::ty_int(ast::TyI64) => { + let lang_def_id = self.tcx().lang_items.i64_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } + ty::ty_int(ast::TyIs(_)) => { + let lang_def_id = self.tcx().lang_items.isize_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } + ty::ty_uint(ast::TyU8) => { + let lang_def_id = self.tcx().lang_items.u8_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } + ty::ty_uint(ast::TyU16) => { + let lang_def_id = self.tcx().lang_items.u16_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } + ty::ty_uint(ast::TyU32) => { + let lang_def_id = self.tcx().lang_items.u32_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } + ty::ty_uint(ast::TyU64) => { + let lang_def_id = self.tcx().lang_items.u64_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } + ty::ty_uint(ast::TyUs(_)) => { + let lang_def_id = self.tcx().lang_items.usize_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } + ty::ty_float(ast::TyF32) => { + let lang_def_id = self.tcx().lang_items.f32_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } + ty::ty_float(ast::TyF64) => { + let lang_def_id = self.tcx().lang_items.f64_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } _ => { } } } + fn assemble_inherent_impl_for_primitive(&mut self, lang_def_id: Option) { + if let Some(impl_def_id) = lang_def_id { + ty::populate_implementations_for_primitive_if_necessary(self.tcx(), impl_def_id); + + self.assemble_inherent_impl_probe(impl_def_id); + } + } + fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: ast::DefId) { // Read the inherent implementation candidates for this type from the // metadata if necessary. diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 5dfe80cfcb2..ab694d26b15 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -16,6 +16,7 @@ use middle::ty; use syntax::ast::{Item, ItemImpl}; use syntax::ast; use syntax::ast_util; +use syntax::codemap::Span; use syntax::visit; use util::ppaux::{Repr, UserString}; @@ -38,6 +39,23 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { } } + fn check_primitive_impl(&self, + impl_def_id: ast::DefId, + lang_def_id: Option, + lang: &str, + ty: &str, + span: Span) { + match lang_def_id { + Some(lang_def_id) if lang_def_id == impl_def_id => { /* OK */ }, + _ => { + self.tcx.sess.span_err( + span, + &format!("only a single inherent implementation marked with `#[lang = \"{}\"]` \ + is allowed for the `{}` primitive", lang, ty)); + } + } + } + /// Checks exactly one impl for orphan rules and other such /// restrictions. In this fn, it can happen that multiple errors /// apply to a specific impl, so just return after reporting one @@ -62,6 +80,125 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { ty::ty_uniq(..) => { self.check_def_id(item, self.tcx.lang_items.owned_box().unwrap()); } + ty::ty_char => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.char_impl(), + "char", + "char", + item.span); + } + ty::ty_str => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.str_impl(), + "str", + "str", + item.span); + } + ty::ty_vec(_, None) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.slice_impl(), + "slice", + "[T]", + item.span); + } + ty::ty_ptr(ty::mt { ty: _, mutbl: ast::MutImmutable }) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.const_ptr_impl(), + "const_ptr", + "*const T", + item.span); + } + ty::ty_ptr(ty::mt { ty: _, mutbl: ast::MutMutable }) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.mut_ptr_impl(), + "mut_ptr", + "*mut T", + item.span); + } + ty::ty_int(ast::TyI8) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.i8_impl(), + "i8", + "i8", + item.span); + } + ty::ty_int(ast::TyI16) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.i16_impl(), + "i16", + "i16", + item.span); + } + ty::ty_int(ast::TyI32) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.i32_impl(), + "i32", + "i32", + item.span); + } + ty::ty_int(ast::TyI64) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.i64_impl(), + "i64", + "i64", + item.span); + } + ty::ty_int(ast::TyIs(_)) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.isize_impl(), + "isize", + "isize", + item.span); + } + ty::ty_uint(ast::TyU8) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.u8_impl(), + "u8", + "u8", + item.span); + } + ty::ty_uint(ast::TyU16) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.u16_impl(), + "u16", + "u16", + item.span); + } + ty::ty_uint(ast::TyU32) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.u32_impl(), + "u32", + "u32", + item.span); + } + ty::ty_uint(ast::TyU64) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.u64_impl(), + "u64", + "u64", + item.span); + } + ty::ty_uint(ast::TyUs(_)) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.usize_impl(), + "usize", + "usize", + item.span); + } + ty::ty_float(ast::TyF32) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.f32_impl(), + "f32", + "f32", + item.span); + } + ty::ty_float(ast::TyF64) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.f64_impl(), + "f64", + "f64", + item.span); + } _ => { span_err!(self.tcx.sess, item.span, E0118, "no base type found for inherent implementation; \ diff --git a/src/test/compile-fail/single-primitive-inherent-impl.rs b/src/test/compile-fail/single-primitive-inherent-impl.rs new file mode 100644 index 00000000000..b2cfcfab78b --- /dev/null +++ b/src/test/compile-fail/single-primitive-inherent-impl.rs @@ -0,0 +1,24 @@ +// Copyright 2015 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. + +// ignore-tidy-linelength + +#![crate_type = "lib"] +#![feature(lang_items)] +#![feature(no_std)] +#![no_std] + +// OK +#[lang = "char"] +impl char {} + +impl char { +//~^ error: only a single inherent implementation marked with `#[lang = "char"]` is allowed for the `char` primitive +}