Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision 6896548fa6cba77903ac279c4d77b434bb762886)
+++ src/AST/Convert.cpp	(revision c36298dc6ce35031df4fda23fb859c772e2c6f5f)
@@ -740,42 +740,18 @@
 
 	const ast::Expr * visit( const ast::ConstantExpr * node ) override final {
-		ConstantExpr *rslt = nullptr;
-		switch ( node->kind ) {
-		case ast::ConstantExpr::Integer:
-			rslt = new ConstantExpr{Constant{
-				get<Type>().accept1( node->result ),
-				node->rep,
-				(unsigned long long) node->intValue()
-			}};
-			break;
-		case ast::ConstantExpr::FloatingPoint:
-			rslt = new ConstantExpr{Constant{
-				get<Type>().accept1(node->result),
-				node->rep,
-				(double) node->floatValue()
-			}};
-			break;
-		case ast::ConstantExpr::String:
-			// Old world:   two types: rslt->constant.type, rslt->result
-			// New workd:   one type: node->result
-			// Both worlds: the outer, expression-level type can change during resolution
-			//              in case of string, that's char[k] before-resolve and char * after
-			// Old world:   the inner Constant type stays what it was built with
-			//              in case of string, that's char[k]
-			// Both worlds: the "rep" field of a string constant is the string value it was initialized from, wrapped in quotes, but not otherwise escaped
-			ast::ptr<ast::Type> charType = nullptr;
-			if (const ast::ArrayType *arrRslt = node->result.as<ast::ArrayType>()) {
-				charType = arrRslt->base;
-			} else {
-				const ast::PointerType *ptrRslt = node->result.as<ast::PointerType>();
-				assert(ptrRslt);
-				charType = ptrRslt->base;
-			}
-			rslt = new ConstantExpr(Constant::from_string(
-				node->rep, get<Type>().accept1(charType)));          // rslt->result is char[k]
-			rslt->set_result( get<Type>().accept1( node->result ) ); // rslt->result is [[ node->rsult ]]
-			break;
-		}
-		assert(rslt);
+		// Old world:   two types: rslt->constant.type, rslt->result
+		// New workd:   one public type: node->result, plus node->underlyer only to support roundtrip conversion
+		//              preserving underlyer because the correct type for string literals is complicated to construct,
+	    //              and distinguishing a string from other literals using the type is hard to do accurately
+		// Both worlds: the outer, expression-level type can change during resolution
+		//              for a string, that's char[k] before-resolve and char * after
+		// Old world:   the inner Constant type stays what it was built with
+		//              for a string, that's char[k] always
+		// Both worlds: the "rep" field of a constant is the C source file fragment that compiles to the desired value
+        //              for a string, that includes outer quotes, backslashes, et al cases from the Literals test
+		ConstantExpr *rslt = new ConstantExpr(Constant(
+			get<Type>().accept1(node->underlyer),
+			node->rep,
+			node->ival));
 		auto expr = visitBaseExpr( node, rslt );
 		this->node = expr;
@@ -2162,73 +2138,12 @@
 	}
 
-	bool isIntlikeConstantType(const Type *t) {
-		if ( const BasicType * basicType = dynamic_cast< const BasicType * >( t ) ) {
-			if ( basicType->isInteger() ) {
-				return true;
-			}
-		} else if ( dynamic_cast< const OneType * >( t ) ) {
-			return true;
-		} else if ( dynamic_cast< const ZeroType * >( t ) ) {
-			return true;
-		} else if ( dynamic_cast< const PointerType * >( t ) ) {
-			// null pointer constants, with zero int-values
-			return true;
-		}
-		return false;
-	}
-
-	int isFloatlikeConstantType(const Type *t) {
-		if ( const BasicType * bty = dynamic_cast< const BasicType * >( t ) ) {
-			if ( ! bty->isInteger() ) {
-				return true;
-			}
-		}
-		return false;
-	}
-
-	int isStringlikeConstantType(const Type *t) {
-		const Type *referentType = nullptr;
-		if ( const ArrayType * aty = dynamic_cast< const ArrayType * >( t ) ) {
-			referentType = aty->base;
-		} else if ( const PointerType * pty = dynamic_cast< const PointerType * >( t ) ) {
-			referentType = pty->base;
-		}
-		if (referentType) {
-			if ( const BasicType * bty = dynamic_cast< const BasicType * >( referentType ) ) {
-			   if ( bty->kind == BasicType::Kind::Char ) {
-				   return true;
-			   }
-			}
-		}
-		return false;
-	}
-
 	virtual void visit( ConstantExpr * old ) override final {
-		ast::ConstantExpr *rslt = nullptr;
-		if (isStringlikeConstantType(old->result)) {
-			rslt = new ast::ConstantExpr(
-				old->location,
-				GET_ACCEPT_1(result, Type), // preserve the expression-level type (old->result, not old->constant.type); see new-to-old
-				old->constant.get_value(),
-				0,
-				ast::ConstantExpr::Kind::String
-			);
-		} else if (isIntlikeConstantType(old->result)) {
-			rslt = new ast::ConstantExpr(
-				old->location,
-				GET_ACCEPT_1(result, Type),
-				old->constant.get_value(),
-				(unsigned long long) old->intValue(),
-				ast::ConstantExpr::Kind::Integer
-			);
-		} else if (isFloatlikeConstantType(old->result)) {
-			rslt = new ast::ConstantExpr(
-				old->location,
-				GET_ACCEPT_1(result, Type),
-				old->constant.get_value(),
-				(double) old->constant.get_dval()
-			);
-		}
-		assert(rslt);
+		ast::ConstantExpr *rslt = new ast::ConstantExpr(
+			old->location,
+			GET_ACCEPT_1(result, Type),
+			old->constant.get_value(),
+			old->constant.ival
+		);
+		rslt->underlyer = getAccept1< ast::Type, Type* >( old->constant.get_type() );
 		this->node = visitBaseExpr( old, rslt );
 	}
