Add support for & operator. (#3055)

Refactor type canonicalization so that we can reuse the same code for
building a `T*` expression and for forming the type of an `&x`
expression.

Add basic computation of expression category in order to check that we
only take the address of durable reference expressions. This is
currently computed on demand rather than being tracked as part of the
semantics node, but in most cases can be determined by looking at only a
single expression, so caching it in the node doesn't seem worthwhile
yet. This decision should be revisited if we start doing more complex
category calculations.

Also add trivial lowering support, but it doesn't work properly yet
because lowering doesn't yet take the expression category into account.
This commit is contained in:
Richard Smith
2023-08-08 20:53:50 +00:00
committed by GitHub
parent 212188a922
commit 62205763a5
17 changed files with 879 additions and 80 deletions
@@ -93,14 +93,34 @@ auto SemanticsHandlePrefixOperator(SemanticsContext& context,
// 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::Not:
value_id = context.ImplicitAsBool(parse_node, value_id);
case TokenKind::Amp: {
// Only durable reference expressions can have their address taken.
switch (
GetSemanticsExpressionCategory(context.semantics_ir(), value_id)) {
case SemanticsExpressionCategory::DurableReference:
break;
case SemanticsExpressionCategory::EphemeralReference:
CARBON_DIAGNOSTIC(AddressOfEphemeralReference, Error,
"Cannot take the address of a temporary object.");
context.emitter().Emit(parse_node, AddressOfEphemeralReference);
break;
default:
CARBON_DIAGNOSTIC(
AddressOfNonReference, Error,
"Cannot take the address of non-reference expression.");
context.emitter().Emit(parse_node, AddressOfNonReference);
break;
}
context.AddNodeAndPush(
parse_node,
SemanticsNode::UnaryOperatorNot::Make(
parse_node, context.semantics_ir().GetNode(value_id).type_id(),
SemanticsNode::AddressOf::Make(
parse_node,
context.GetPointerType(
parse_node,
context.semantics_ir().GetNode(value_id).type_id()),
value_id));
return true;
}
case TokenKind::Const: {
// `const (const T)` is probably not what the developer intended.
@@ -121,6 +141,18 @@ auto SemanticsHandlePrefixOperator(SemanticsContext& context,
return true;
}
case TokenKind::Not:
value_id = context.ImplicitAsBool(parse_node, value_id);
context.AddNodeAndPush(
parse_node,
SemanticsNode::UnaryOperatorNot::Make(
parse_node, context.semantics_ir().GetNode(value_id).type_id(),
value_id));
return true;
case TokenKind::Star:
return context.TODO(parse_node, llvm::formatv("Handle {0}", token_kind));
default:
return context.TODO(parse_node, llvm::formatv("Handle {0}", token_kind));
}