From 14178efa5dd48968c951b3266c6a9bebcd914884 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Mon, 22 Apr 2019 13:29:23 +0200
Subject: [PATCH 1/2] Symbol name predicate list printed `+` excessively

---
 src/librustc_codegen_utils/symbol_names.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs
index 211d725e39d57..4a5d356096eec 100644
--- a/src/librustc_codegen_utils/symbol_names.rs
+++ b/src/librustc_codegen_utils/symbol_names.rs
@@ -427,7 +427,7 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> {
         mut self,
         predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
     ) -> Result<Self::DynExistential, Self::Error> {
-        let mut first = false;
+        let mut first = true;
         for p in predicates {
             if !first {
                 write!(self, "+")?;

From 5b9848912a85e28d000602fc2e81bad9c2f2a981 Mon Sep 17 00:00:00 2001
From: Oliver Scherer <github35764891676564198441@oli-obk.de>
Date: Mon, 22 Apr 2019 13:53:52 +0200
Subject: [PATCH 2/2] Make the `type_name` intrinsic's output deterministic

---
 src/librustc/mir/interpret/allocation.rs      |  10 +-
 src/librustc_codegen_llvm/intrinsic.rs        |   5 +-
 src/librustc_codegen_ssa/mir/operand.rs       |  12 +-
 src/librustc_mir/const_eval.rs                |   4 +-
 src/librustc_mir/interpret/intrinsics.rs      |   3 +
 .../interpret/intrinsics/type_name.rs         | 228 ++++++++++++++++++
 src/librustc_mir/interpret/mod.rs             |   2 +
 src/test/run-pass/issues/issue-21058.rs       |  67 ++++-
 src/test/run-pass/tydesc-name.rs              |   2 +-
 9 files changed, 306 insertions(+), 27 deletions(-)
 create mode 100644 src/librustc_mir/interpret/intrinsics/type_name.rs

diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs
index 9549a5af5af5c..856b47c7e1b6f 100644
--- a/src/librustc/mir/interpret/allocation.rs
+++ b/src/librustc/mir/interpret/allocation.rs
@@ -12,6 +12,7 @@ use std::ops::{Deref, DerefMut};
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_macros::HashStable;
 use rustc_target::abi::HasDataLayout;
+use std::borrow::Cow;
 
 /// Used by `check_bounds` to indicate whether the pointer needs to be just inbounds
 /// or also inbounds of a *live* allocation.
@@ -112,10 +113,11 @@ impl AllocationExtra<()> for () { }
 
 impl<Tag, Extra> Allocation<Tag, Extra> {
     /// Creates a read-only allocation initialized by the given bytes
-    pub fn from_bytes(slice: &[u8], align: Align, extra: Extra) -> Self {
-        let undef_mask = UndefMask::new(Size::from_bytes(slice.len() as u64), true);
+    pub fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align, extra: Extra) -> Self {
+        let bytes = slice.into().into_owned();
+        let undef_mask = UndefMask::new(Size::from_bytes(bytes.len() as u64), true);
         Self {
-            bytes: slice.to_owned(),
+            bytes,
             relocations: Relocations::new(),
             undef_mask,
             align,
@@ -124,7 +126,7 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
         }
     }
 
-    pub fn from_byte_aligned_bytes(slice: &[u8], extra: Extra) -> Self {
+    pub fn from_byte_aligned_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, extra: Extra) -> Self {
         Allocation::from_bytes(slice, Align::from_bytes(1).unwrap(), extra)
     }
 
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 9ae0e26196d94..060c295eb7af1 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -20,7 +20,6 @@ use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, Primitive};
 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
 use rustc::hir;
 use syntax::ast::{self, FloatTy};
-use syntax::symbol::LocalInternedString;
 
 use rustc_codegen_ssa::traits::*;
 
@@ -213,8 +212,8 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
             }
             "type_name" => {
                 let tp_ty = substs.type_at(0);
-                let ty_name = LocalInternedString::intern(&tp_ty.to_string());
-                self.const_str_slice(ty_name)
+                let ty_name = rustc_mir::interpret::type_name(self.tcx, tp_ty);
+                OperandRef::from_const(self, ty_name).immediate_or_packed_pair(self)
             }
             "type_id" => {
                 self.const_u64(self.tcx.type_id_hash(substs.type_at(0)))
diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs
index ec471a1323eab..0ae2fbe8071ad 100644
--- a/src/librustc_codegen_ssa/mir/operand.rs
+++ b/src/librustc_codegen_ssa/mir/operand.rs
@@ -68,11 +68,11 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> {
     pub fn from_const<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
         bx: &mut Bx,
         val: &'tcx ty::Const<'tcx>
-    ) -> Result<Self, ErrorHandled> {
+    ) -> Self {
         let layout = bx.layout_of(val.ty);
 
         if layout.is_zst() {
-            return Ok(OperandRef::new_zst(bx, layout));
+            return OperandRef::new_zst(bx, layout);
         }
 
         let val = match val.val {
@@ -110,14 +110,14 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> {
                 OperandValue::Pair(a_llval, b_llval)
             },
             ConstValue::ByRef(ptr, alloc) => {
-                return Ok(bx.load_operand(bx.from_const_alloc(layout, alloc, ptr.offset)));
+                return bx.load_operand(bx.from_const_alloc(layout, alloc, ptr.offset));
             },
         };
 
-        Ok(OperandRef {
+        OperandRef {
             val,
             layout
-        })
+        }
     }
 
     /// Asserts that this operand refers to a scalar and returns
@@ -468,7 +468,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             mir::Operand::Constant(ref constant) => {
                 let ty = self.monomorphize(&constant.ty);
                 self.eval_mir_constant(constant)
-                    .and_then(|c| OperandRef::from_const(bx, c))
+                    .map(|c| OperandRef::from_const(bx, c))
                     .unwrap_or_else(|err| {
                         match err {
                             // errored or at least linted
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 0637c7b058882..2c68ed58d50d4 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -116,7 +116,9 @@ fn op_to_const<'tcx>(
                     ptr.offset.bytes(),
                 ),
                 Scalar::Raw { .. } => (
-                    ecx.tcx.intern_const_alloc(Allocation::from_byte_aligned_bytes(b"", ())),
+                    ecx.tcx.intern_const_alloc(Allocation::from_byte_aligned_bytes(
+                        b"" as &[u8], (),
+                    )),
                     0,
                 ),
             };
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index d9721a8cadff9..34e9b4972a16d 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -14,6 +14,9 @@ use super::{
     Machine, PlaceTy, OpTy, InterpretCx,
 };
 
+mod type_name;
+
+pub use type_name::*;
 
 fn numeric_intrinsic<'tcx, Tag>(
     name: &str,
diff --git a/src/librustc_mir/interpret/intrinsics/type_name.rs b/src/librustc_mir/interpret/intrinsics/type_name.rs
new file mode 100644
index 0000000000000..48b02d8e11b60
--- /dev/null
+++ b/src/librustc_mir/interpret/intrinsics/type_name.rs
@@ -0,0 +1,228 @@
+use rustc::ty::{
+    TyCtxt, Ty,
+    subst::{UnpackedKind, Kind},
+    print::{Printer, PrettyPrinter, Print},
+    self,
+};
+use rustc::hir::map::{DefPathData, DisambiguatedDefPathData};
+use rustc::hir::def_id::CrateNum;
+use std::fmt::Write;
+use rustc::mir::interpret::{Allocation, ConstValue};
+
+struct AbsolutePathPrinter<'a, 'tcx> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    path: String,
+}
+
+impl<'tcx> Printer<'tcx, 'tcx> for AbsolutePathPrinter<'_, 'tcx> {
+    type Error = std::fmt::Error;
+
+    type Path = Self;
+    type Region = Self;
+    type Type = Self;
+    type DynExistential = Self;
+    type Const = Self;
+
+    fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
+        self.tcx
+    }
+
+    fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
+        Ok(self)
+    }
+
+    fn print_type(self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
+        match ty.sty {
+            // types without identity
+            | ty::Bool
+            | ty::Char
+            | ty::Int(_)
+            | ty::Uint(_)
+            | ty::Float(_)
+            | ty::Str
+            | ty::Array(_, _)
+            | ty::Slice(_)
+            | ty::RawPtr(_)
+            | ty::Ref(_, _, _)
+            | ty::FnPtr(_)
+            | ty::Never
+            | ty::Tuple(_)
+            | ty::Dynamic(_, _)
+            | ty::Adt(..)
+            | ty::Foreign(_)
+            // should be unreachable, but there's no hurt in printing it (and better than ICEing)
+            | ty::Error
+            => self.pretty_print_type(ty),
+            | ty::Infer(_)
+            | ty::Bound(_, _)
+            | ty::Param(_)
+            | ty::Placeholder(_)
+            | ty::Projection(_)
+            | ty::UnnormalizedProjection(_)
+            | ty::GeneratorWitness(_)
+            => bug!(
+                "{:#?} in `type_name` should not happen because we are always monomorphized",
+                ty,
+            ),
+            // types with identity (print the module path instead)
+            | ty::FnDef(did, substs)
+            | ty::Opaque(did, substs)
+            => self.print_def_path(did, substs),
+            ty::Closure(did, substs) => self.print_def_path(did, substs.substs),
+            ty::Generator(did, substs, _) => self.print_def_path(did, substs.substs),
+        }
+    }
+
+    fn print_const(
+        self,
+        _: &'tcx ty::Const<'tcx>,
+    ) -> Result<Self::Const, Self::Error> {
+        // don't print constants to the user
+        Ok(self)
+    }
+
+    fn print_dyn_existential(
+        mut self,
+        predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>,
+    ) -> Result<Self::DynExistential, Self::Error> {
+        let mut first = true;
+        for p in predicates {
+            if !first {
+                write!(self, "+")?;
+            }
+            first = false;
+            self = p.print(self)?;
+        }
+        Ok(self)
+    }
+
+    fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
+        self.path.push_str(&self.tcx.original_crate_name(cnum).as_str());
+        Ok(self)
+    }
+
+    fn path_qualified(
+        self,
+        self_ty: Ty<'tcx>,
+        trait_ref: Option<ty::TraitRef<'tcx>>,
+    ) -> Result<Self::Path, Self::Error> {
+        self.pretty_path_qualified(self_ty, trait_ref)
+    }
+
+    fn path_append_impl(
+        self,
+        print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+        _disambiguated_data: &DisambiguatedDefPathData,
+        self_ty: Ty<'tcx>,
+        trait_ref: Option<ty::TraitRef<'tcx>>,
+    ) -> Result<Self::Path, Self::Error> {
+        self.pretty_path_append_impl(
+            |mut cx| {
+                cx = print_prefix(cx)?;
+
+                cx.path.push_str("::");
+
+                Ok(cx)
+            },
+            self_ty,
+            trait_ref,
+        )
+    }
+
+    fn path_append(
+        mut self,
+        print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+        disambiguated_data: &DisambiguatedDefPathData,
+    ) -> Result<Self::Path, Self::Error> {
+        self = print_prefix(self)?;
+
+        // Skip `::{{constructor}}` on tuple/unit structs.
+        match disambiguated_data.data {
+            DefPathData::Ctor => return Ok(self),
+            _ => {}
+        }
+
+        self.path.push_str("::");
+
+        self.path.push_str(&disambiguated_data.data.as_interned_str().as_str());
+        Ok(self)
+    }
+
+    fn path_generic_args(
+        mut self,
+        print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+        args: &[Kind<'tcx>],
+    ) -> Result<Self::Path, Self::Error> {
+        self = print_prefix(self)?;
+        let args = args.iter().cloned().filter(|arg| {
+            match arg.unpack() {
+                UnpackedKind::Lifetime(_) => false,
+                _ => true,
+            }
+        });
+        if args.clone().next().is_some() {
+            self.generic_delimiters(|cx| cx.comma_sep(args))
+        } else {
+            Ok(self)
+        }
+    }
+}
+impl PrettyPrinter<'tcx, 'tcx> for AbsolutePathPrinter<'_, 'tcx> {
+    fn region_should_not_be_omitted(
+        &self,
+        _region: ty::Region<'_>,
+    ) -> bool {
+        false
+    }
+    fn comma_sep<T>(
+        mut self,
+        mut elems: impl Iterator<Item = T>,
+    ) -> Result<Self, Self::Error>
+        where T: Print<'tcx, 'tcx, Self, Output = Self, Error = Self::Error>
+    {
+        if let Some(first) = elems.next() {
+            self = first.print(self)?;
+            for elem in elems {
+                self.path.push_str(", ");
+                self = elem.print(self)?;
+            }
+        }
+        Ok(self)
+    }
+
+    fn generic_delimiters(
+        mut self,
+        f: impl FnOnce(Self) -> Result<Self, Self::Error>,
+    ) -> Result<Self, Self::Error> {
+        write!(self, "<")?;
+
+        self = f(self)?;
+
+        write!(self, ">")?;
+
+        Ok(self)
+    }
+}
+
+impl Write for AbsolutePathPrinter<'_, '_> {
+    fn write_str(&mut self, s: &str) -> std::fmt::Result {
+        Ok(self.path.push_str(s))
+    }
+}
+
+/// Produces an absolute path representation of the given type. See also the documentation on
+/// `std::any::type_name`
+pub fn type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
+    let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path;
+    let len = path.len();
+    let alloc = Allocation::from_byte_aligned_bytes(path.into_bytes(), ());
+    let alloc = tcx.intern_const_alloc(alloc);
+    tcx.mk_const(ty::Const {
+        val: ConstValue::Slice {
+            data: alloc,
+            start: 0,
+            end: len,
+        },
+        ty: tcx.mk_static_str(),
+    })
+}
diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs
index ea358389ddb76..ed389a8df94ab 100644
--- a/src/librustc_mir/interpret/mod.rs
+++ b/src/librustc_mir/interpret/mod.rs
@@ -32,3 +32,5 @@ pub use self::operand::{ScalarMaybeUndef, Immediate, ImmTy, Operand, OpTy};
 pub use self::visitor::{ValueVisitor, MutValueVisitor};
 
 pub use self::validity::RefTracking;
+
+pub use self::intrinsics::type_name;
diff --git a/src/test/run-pass/issues/issue-21058.rs b/src/test/run-pass/issues/issue-21058.rs
index 0483e62fd2121..3efa94ce6835c 100644
--- a/src/test/run-pass/issues/issue-21058.rs
+++ b/src/test/run-pass/issues/issue-21058.rs
@@ -2,21 +2,64 @@
 #![allow(dead_code)]
 #![feature(core_intrinsics)]
 
+use std::fmt::Debug;
+
 struct NT(str);
 struct DST { a: u32, b: str }
 
+macro_rules! check {
+    (val: $ty_of:expr, $expected:expr) => {
+        assert_eq!(type_name_of_val($ty_of), $expected);
+    };
+    ($ty:ty, $expected:expr) => {
+        assert_eq!(unsafe { std::intrinsics::type_name::<$ty>()}, $expected);
+    };
+}
+
 fn main() {
     // type_name should support unsized types
-    assert_eq!(unsafe {(
-        // Slice
-        std::intrinsics::type_name::<[u8]>(),
-        // str
-        std::intrinsics::type_name::<str>(),
-        // Trait
-        std::intrinsics::type_name::<dyn Send>(),
-        // Newtype
-        std::intrinsics::type_name::<NT>(),
-        // DST
-        std::intrinsics::type_name::<DST>()
-    )}, ("[u8]", "str", "dyn std::marker::Send", "NT", "DST"));
+    check!([u8], "[u8]");
+    check!(str, "str");
+    check!(dyn Send, "dyn core::marker::Send");
+    check!(NT, "issue_21058::NT");
+    check!(DST, "issue_21058::DST");
+    check!(&i32, "&i32");
+    check!(&'static i32, "&i32");
+    check!((i32, u32), "(i32, u32)");
+    check!(val: foo(), "issue_21058::Foo");
+    check!(val: Foo::new, "issue_21058::Foo::new");
+    check!(val:
+        <Foo as Debug>::fmt,
+        "<issue_21058::Foo as core::fmt::Debug>::fmt"
+    );
+    check!(val: || {}, "issue_21058::main::{{closure}}");
+    bar::<i32>();
+}
+
+trait Trait {
+    type Assoc;
+}
+
+impl Trait for i32 {
+    type Assoc = String;
+}
+
+fn bar<T: Trait>() {
+    check!(T::Assoc, "alloc::string::String");
+    check!(T, "i32");
+}
+
+fn type_name_of_val<T>(_: T) -> &'static str {
+    unsafe { std::intrinsics::type_name::<T>() }
+}
+
+#[derive(Debug)]
+struct Foo;
+
+impl Foo {
+    fn new() -> Self { Foo }
+}
+
+fn foo() -> impl Debug {
+    Foo
 }
diff --git a/src/test/run-pass/tydesc-name.rs b/src/test/run-pass/tydesc-name.rs
index 94de30e88e1fb..91578b71d04ae 100644
--- a/src/test/run-pass/tydesc-name.rs
+++ b/src/test/run-pass/tydesc-name.rs
@@ -11,6 +11,6 @@ struct Foo<T> {
 pub fn main() {
     unsafe {
         assert_eq!(type_name::<isize>(), "isize");
-        assert_eq!(type_name::<Foo<usize>>(), "Foo<usize>");
+        assert_eq!(type_name::<Foo<usize>>(), "tydesc_name::Foo<usize>");
     }
 }