Basic semantic checking for pointer types and const-qualified types. (#3038)

Semantic handling for use of `T*` and `const T` as types.

There's no way to form values of these types yet, and no conversions for
them are supported.

Factor out the common code to canonicalize types using a folding set,
and switch to using the same folding set for all kinds of type by adding
the kind as part of the folding set key.

Improve type printing to not include the `as type` portion when the type
is printed in a context within another type where a conversion to `type`
is implied, as in `{}*` and pre-existing cases like `({}, {}) as type`
(which we used to print as `({} as type, {} as type}) as type`.
This commit is contained in:
Richard Smith
2023-08-02 23:19:52 +00:00
committed by GitHub
parent e448ea5a7c
commit c8b42379a4
20 changed files with 905 additions and 87 deletions
@@ -25,7 +25,7 @@ auto SemanticsHandleInfixOperator(SemanticsContext& context,
SemanticsNode::BinaryOperatorAdd::Make(
parse_node, context.semantics_ir().GetNode(lhs_id).type_id(),
lhs_id, rhs_id));
break;
return true;
case TokenKind::And:
case TokenKind::Or: {
@@ -49,19 +49,33 @@ auto SemanticsHandleInfixOperator(SemanticsContext& context,
SemanticsNode::BlockArg::Make(
parse_node, context.semantics_ir().GetNode(rhs_id).type_id(),
resume_block_id));
break;
return true;
}
default:
return context.TODO(parse_node, llvm::formatv("Handle {0}", token_kind));
}
return true;
}
auto SemanticsHandlePostfixOperator(SemanticsContext& context,
ParseTree::Node parse_node) -> bool {
return context.TODO(parse_node, "HandlePostfixOperator");
auto value_id = context.node_stack().PopExpression();
// Figure out the operator for the token.
auto token = context.parse_tree().node_token(parse_node);
switch (auto token_kind = context.tokens().GetKind(token)) {
case TokenKind::Star: {
auto inner_type_id = context.ExpressionAsType(parse_node, value_id);
context.AddNodeAndPush(
parse_node,
SemanticsNode::PointerType::Make(
parse_node, SemanticsTypeId::TypeType, inner_type_id));
return true;
}
default:
CARBON_FATAL() << "Unexpected postfix operator " << token_kind;
}
}
auto SemanticsHandlePrefixOperator(SemanticsContext& context,
@@ -78,13 +92,30 @@ auto SemanticsHandlePrefixOperator(SemanticsContext& context,
SemanticsNode::UnaryOperatorNot::Make(
parse_node, context.semantics_ir().GetNode(value_id).type_id(),
value_id));
break;
return true;
case TokenKind::Const: {
// `const (const T)` is probably not what the developer intended.
// TODO: Detect `const (const T)*` and suggest moving the `*` inside the
// parentheses.
if (context.semantics_ir().GetNode(value_id).kind() ==
SemanticsNodeKind::ConstType) {
CARBON_DIAGNOSTIC(RepeatedConst, Warning,
"`const` applied repeatedly to the same type has no "
"additional effect.");
context.emitter().Emit(parse_node, RepeatedConst);
}
auto inner_type_id = context.ExpressionAsType(parse_node, value_id);
context.AddNodeAndPush(
parse_node,
SemanticsNode::ConstType::Make(parse_node, SemanticsTypeId::TypeType,
inner_type_id));
return true;
}
default:
return context.TODO(parse_node, llvm::formatv("Handle {0}", token_kind));
}
return true;
}
auto SemanticsHandleShortCircuitOperand(SemanticsContext& context,
@@ -115,7 +146,7 @@ auto SemanticsHandleShortCircuitOperand(SemanticsContext& context,
break;
default:
CARBON_FATAL() << "Unexpected short-circuiting operator " << parse_node;
CARBON_FATAL() << "Unexpected short-circuiting operator " << token_kind;
}
// Create a block for the right-hand side and for the continuation.