-->

Why is this assignment ambiguous?

2019-07-16 13:02发布

问题:

Please note that this question is not about how to change the code below to make it work; rather, I am looking for some insight on why a compiler would find this assignment ambiguous:

entity assignment_to_aggregates is
end;

architecture example of assignment_to_aggregates is
    type vowel_type is (a, e, i, o, u);
    type consonant_type is (b, c, d, f, g);
    type vowel_consonant_pair is record
        vowel: vowel_type;
        consonant: consonant_type;
    end record;

    signal my_vowel: vowel_type;
    signal my_consonant: consonant_type;
begin
    (my_vowel, my_consonant) <= (a, b); -- Doesn't work: "Ambiguous types in signal assignment statement."
end;

I have tested it with Modelsim Altera 10.1b and GHDL 0.29.1 and I'm seeing the following error messages:

VCOM: (vcom-1349) Ambiguous types in signal assignment statement
    Possible target types are:
        vowel_consonant_pair
        ieee.std_logic_1164.STD_ULOGIC_VECTOR
        std.STANDARD.TIME_VECTOR
        std.STANDARD.REAL_VECTOR
        std.STANDARD.INTEGER_VECTOR
        std.STANDARD.BIT_VECTOR
        std.STANDARD.BOOLEAN_VECTOR
        std.STANDARD.STRING

GHDL: type of waveform is unknown, use type qualifier

Of course, if I declare a new type explicitly (vowel_consonant_pair in the sample code) and use type qualification, it works fine:

(my_vowel, my_consonant) <= vowel_consonant_pair'(a, b); -- Works fine

But why should this be necessary, if there is absolutely no other type that could match the aggregate on the right-hand side of the assignment? Is this a tool problem, or is this a VHDL semantics problem? If the latter, could someone please provide a LRM reference?

回答1:

Quoted from my answer to the previous question:

IEEE Std 1076-1993, 8.4 Signal assignment statement (see -2008, 10.5/10.5.2.1):

If the target of the signal assignment statement is in the form of an aggregate, then the type of the aggregate must be determinable from the context, excluding the aggregate itself but including the fact that the type of the aggregate must be a composite type.

Add a bit more:

-1993, 0.2 Structure and terminology of this document (see -2008, 1.3/1.3.1:

Additionally, the word "must" is used to indicate mandatory weight. This word is preferred over the more common "shall," as "must" denotes a different meaning to different readers of this standard.

It's a semantic restriction, 'must' carries a mandatory weight, a condition that must be met will otherwise generate and error in VHDL. The type of the aggregate isn't known without qualification. Note 'that' must has been supplanted by 'shall' in the 2008 version of the standard.

The type in question here is of the target (the left hand side). We're bound by to the requirement in the section on sequential signal assignment for the concurrent signal assignment statement by the first sentence of the section on concurrent signal assignment, IEEE Std 1076-2008:

11.6 Concurrent signal assignment statements

A concurrent signal assignment statement represents an equivalent process statement that assigns values to signals.

(Also found in -1993, 9.5).

Type is generally carried as an attribute on a name, but the aggregate isn't a named object. It's possible to get the type from the right hand side except it's an aggregate too:

(my_vowel, my_consonant) <= (a, b);

Nick Gasson's VHDL analyzer/simulator nvc points a little more elegantly to where to fix the problem:

nvc -a assignment_to_aggregate.vhdl  
** Error: no composite type in context
      File assignment_to_aggregate.vhdl, Line 11  
        (my_vowel, my_consonant) <= (a,b);  
                                    ^^^^^

(Following a fix for an elaboration 'crash' caused by a missing semantic check found using a previous stackoverflow VHDL question).

How can you type the right hand side?

From IEEE Std 1076-1993:

7.3.4 Qualified expressions

A qualified expression is a basic operation (see the introduction to Section 3)that is used to explicitly state the type, and possibly the subtype, of an operand that is an expression or an aggregate.

 qualified_expression ::=
        type_mark ' ( expression )
      | type_mark ' aggregate

The operand must have the same type as the base type of the type mark. The value of a qualified expression is the value of the operand. The evaluation of a qualified expression evaluates the operand and checks that its value belongs to the subtype denoted by the type mark.

NOTE--Whenever the type of an enumeration literal or aggregate is not known from the context, a qualified expression can be used to state the type explicitly.

There isn't a glossary definition of 'context' in any of the VHDL standard versions. A working definition might include the notion that the declaration for something is visible, which isn't the case for the type of an aggregate without qualification.

I wrote the answer to the previous question and I introduced the record type declaration specifically to address the lack of ability to decorate the aggregate with a type mark in a qualified expression. Note that there is no subtype (signal and) declared as a vowel_consonant_pair record. The type declaration was needed, not an actual record.

Also note I submitted a bug on ghdl-0.31 which has been fixed source tree but there hasn't been an actual release since - ghdl barfs when it can't discern the type of an aggregate. A newer version of ghdl won't crash if you don't qualify the expression.

Questions on stackoverflow generally make a wonderful contribution to improving open source VHDL tools.

I keep the standards handy and usually am able to cite chapter and verse. It can be a lot of work, there's very little you can't find out about VHDL by a thorough reading of the standard although there isn't a permuted index and you have to be inculcated in the terminology to understand the significance of what you read.

Like the answer to your current question a reference in the standard can lead to another part of the standard.

The comp.lang.vhdl FAQ quoted by Jim Lewis in a recent answer is a wonderful reference but sometimes lacks authoritative emphasis, using references to the -1993 standard sparingly.

See the FAQ, 4.2.18 How to Resolve Type Ambiguities in Expressions.

Your confusion seems to stem from the Modelsim error messages suggesting 'possible' types needed to resolve ambiguity. Note the first sentence in the 4.2.18:

VHDL is a strongly typed language. Hence, the compiler does not perform any implicit type conversions or attempt to "guess" the type of an expression.

And an aggregate is an expression (See 7.3.2/9.3.3 Aggregates, -1993/-2008).

Most of the possible type declarations provided by the vcom errror message are not accurate for the aggregate which is comprised of two disparate type elements - a is an enumeration name for a value of vowel_type and b is an enumeration for a value of consonant_type.

The types provided with the vcom error appear to be all the composite types made visible by local declaration (vowel_consonant_pair) or context clause (std_ulogic_vector, real_vector, integer_vector, bit_vector, boolean_vector, string, collectively found in ieee.std_logic_1164 or std.standard).

Of that bunch only one would be valid (vowel_consonant_pair). Notice the VHDL analyzer didn't guess, instead requiring the correct type to be made available from context as an object decoration (type qualification) as a result of a semantic rule (Signal assignment statement 8.4/10.5.2.1, "...the type of the aggregate must be determinable from the context, excluding the aggregate itself but including the fact that the type of the aggregate must be a composite type"). The rule giving the list of possible candidates, available composite types while disallowing guessing ("excluding the aggregate itself").