allow inherent implementations on primitives

This commit is contained in:
Jorge Aparicio 2015-03-10 23:12:55 -05:00
parent 92dd995e17
commit 8570739880
5 changed files with 278 additions and 0 deletions

View File

@ -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;

View File

@ -788,6 +788,9 @@ pub struct ctxt<'tcx> {
/// is used for lazy resolution of traits.
pub populated_external_traits: RefCell<DefIdSet>,
/// The set of external primitive inherent implementations that have been read.
pub populated_external_primitive_impls: RefCell<DefIdSet>,
/// Borrows
pub upvar_capture_map: RefCell<UpvarCaptureMap>,
@ -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,

View File

@ -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<ast::DefId>) {
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.

View File

@ -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<ast::DefId>,
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; \

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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
}